I downloaded iAdSuite and looked into ADBannerNavigation.
Inside, I changed the RootViewController to subclass TextViewController in order to take advantage of the iAd banner resizing. I want to display ads on the RootView as well.
This is now RootViewController.h:
#import <UIKit/UIKit.h>
#import "TextViewController.h"
#interface RootViewController : TextViewController
#end
Everything else is the same. When I compile and run, no ads show up in RootView, and when I click into TextView, ads suddenly show up.
When I click to go back, there is now white space in RootView.
WHY?
How do you remove the white space?
Found the error in how I was removing the ADBannerView.
iAd Suite tells us to:
Note: If your application has multiple tabs or views displaying an iAd banner, be sure to share a single instance of ADBannerView across each view. Then, before your users navigate to a new view, set the shared instance’s delegate property to nil, remove it from the old view hierarchy, then add the same instance to the opening view and set its delegate to the appropriate view controller. The "AdBannerNavigation" sample shows this technique.
So, in my iADBannerView.m, I have:
- (void)viewWillDisappear:(BOOL)animated{
[self removeADBannerFromView];
[super viewWillDisappear:animated];
}
- (void)removeADBannerFromView{
NSLog(#"ad removed from view");
ADBannerView *adBanner = SharedAdBannerView;
adBanner.delegate = nil;
[adBanner removeFromSuperview];
}
- (void)dealloc{
// we are being called here when we navigate away from this view controller,
// so go ahead and reset our AdBannerView for the next time
//
ADBannerView *adBanner = SharedAdBannerView;
adBanner.delegate = nil;
[adBanner removeFromSuperview];
[contentView release]; contentView = nil;
[super dealloc];
}
By setting breakpoints, I saw that by exiting a view, viewWillDisappear was being called on view1, then viewWillAppear on view0 and then dealloc on view1.
The problem was that view1 already removed the ADBannerView from the view, so [adBanner removeFromSuperView] was removing the Ad from view0.
Problem solved by removing offending code from the dealloc method.
Related
I load InfoViewController's view as a subview in MainViewController like this (declared in .h):
- (void)viewDidLoad
{
[super viewDidLoad];
infoViewController = [[InfoViewController alloc] initWithNibName:#"InfoViewController" bundle:nil];
mainInfoView = (MainInfoView *)[mainInfoViewController view];
}
(MainViewController is push-presented from a segue from a tableviewcontroller cell and has a navigation bar.)
This is in InfoViewController's viewDidLoad to set the size of view:
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.frame = CGRectMake(130, 0, 178, 299);
}
In the Size inspector for InfoViewController I've set the same size (with: 178, height: 299).
I disabled "Use Autolayout" both for InfoViewController in XIB and for the MainViewController in Storyboard.
I have some UILabels, UITextViews and UIImageViews in the InfoViewController. They are declared with properties in .h and synthesized in .m. and connected to the elements in the XIB. Their content is defined in viewWillAppear of MainViewController like this:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
infoViewController.kategoriLabel.text = [[objArr objectAtIndex:detailIndex] objectForKey:#"Type"];
}
When I run the app and this view is entered, some of the labels, images and textViews are suddenly placed in what appears to be random locations. This is only happening to some of the elements.
I have done this same thing in another app and it works fine on both simulator (iPhone 4 ver 6,0) and iPhone 5 device, but in this app it just gets messy on both.
I cannot seem to find anything different anywhere in the Utilities or anywhere else when I compare the apps.
If you have experienced something similar and solved it or if you might know what could be causing it, I will appreciate your answer. Thanks.
PS. I'm using Xcode 4.5.1
I had a different problem, but my brute-force resolution might work for you as well. In my case, I wanted to disable the nav bar on the final item in a series of view controllers. IB, though, won't let you remove the Nav bar so I had to do it manually in viewWillAppear. However, once the bar was hidden, IOS shifted up all my buttons and objects that had been defined in IB by the height of the (now hidden) nav bar.
I resorted to the following in the Controller's viewWillAppear. (objects tended to shift visibly when I tried this in viewWillAppear)
-(void) viewWillAppear:(BOOL)animated
{
//turn off nav bar
[[self navigationController]setNavigationBarHidden:YES animated:NO];
//correct positions of items that shift when the bar disappears
myThing.center = CGPointMake(desired_x_coord, desired_y_coord);
myOtherThing.center = CGPointMake(desired_x_coord2, desired_y_coord2);
...etc...
//don't forget to call the base class
[super viewWillAppear:animated];
}
Annoying, but worked. If you can't find the source of your objects moving, you could try forcing their positions using viewWillAppear.
Please help! It seems to simple, but, sorry, I 'have' to ask, as it's not working. I have a main view with a UITableView. On swiping, am adding a subview which has a picker and a button. It works fine: I swipe & the subview appears in front of the main view, but when I click the picker or the button, nothing really happens in the subview; instead the components in the main view (which is beneath the subview) get called! Am saying this for sure, because, in the main view, I have a picture beneath the added-subview (tapping the picture opens a new view). Now, when I tap the picker in the subview (the picture is beneath it in the main view), the picture gets tapped & the new view opens up! How is this possible?
This is the subview (in Interface Builder)
Here's my code snippet:
In my MainViewController.m (viewCtrlrFilter is the subview added when the user swipes in the main view)):
....
self.viewCtrlrFilter = (ViewController_Filter *) [myStoryboard instantiateViewControllerWithIdentifier:kNameViewCtrlrFilter];
...
// This is called when the user pans/swipes
// This does work fine; the subview gets added & is visible
[self.viewCtrlrFilter initializeView];
[self.viewCtrlr.view setFrame:CGRectMake(310.0, 220.0, 243.0, 208.0)];
[self.view addSubview:self.viewCtrlrFilter.view];
...
From ViewController_Filter.h :
...
// This implements the Picker Delegate & DataSource
// which I have wired to the picker in IB
#interface ViewController_FilterPhotographers : UIViewController <UIPickerViewDelegate, UIPickerViewDataSource>
...
// This is called when the button in the subview
// (screenshot above) is pressed
// It's wired through the IB
-(IBAction) buttonPressed:(id) sender;
...
From ViewController_Filter.m :
-(void) initializeView {
self.myPicker.delegate = self;
self.myPicker.dataSource = self;
self.myPicker.showsSelectionIndicator = YES;
CGRect rect = self.myPicker.frame;
rect.origin = CGPointMake(0.0, 0.0);
self.myPicker.frame = rect;
self.myPicker.transform = CGAffineTransformMakeScale(0.625,0.625);
[self.myPicker becomeFirstResponder];
}
...
-(IBAction) buttonPressed:(id) sender {
NSLog(#"hi");
}
...
- (void)viewDidLoad
{
[super viewDidLoad];
[self initializeView];
}
...
When the user swipes, the subview does get added (the picker & button are seen), but when I click the button, the IBAction method isn't getting called. Instead, funnily, the component in the main view (beneath the subview) is getting called!
It works now! Looks like setting the datasource & delegate for the picker view from both the code & IB was a problem. I set it from IB & removed it from code. It works fine now!
I have an iPhone view controller that's initialized with a XIB.
If a view controller's view is not visible when a memory warning comes through, it sets its view to nil (releasing it). But when an overlapping view is dismissed and the cleared-out view becomes visible again, Cocoa doesn't reload it from the XIB; it simply creates a blank one. This leaves a blank white screen, and a broken app.
The Apple doc for UIViewController's loadView method says, "If the view controller has an associated nib file, this method loads the view from the nib file. A view controller has an associated nib file if the nibName property returns a non-nil value." So I overrode loadView simply to check nibName after initializing the controller, and nibName is correct. So subsequent calls to loadView should be reloading from the XIB. I verified that loadView is called again after the memory warning.
UPDATE: With more testing and logging, I've determined that after the second viewDidLoad call, the view's IBOutlets are non-nil. Since I set them to nil in viewDidUnload, I conclude that the view was indeed reloaded from the XIB. So why is it showing up as an all-white screen?
Thanks for any insight.
Here's viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
_photoViewController = [[EGOSimplePhotoViewController alloc] initWithPhotoSource:_photoSource
scrollView:bigImageScrollView
enclosingView:photoSquare];
_photoViewController.delegate = self;
if(_progressHUD == nil)
{
if(self.navigationController.view != nil)
{
_progressHUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
}
else
{
_progressHUD = [[MBProgressHUD alloc] initWithView:self.view];
}
}
// Add HUD to screen.
if(self.navigationController.view != nil)
{
[self.navigationController.view addSubview:_progressHUD];
}
else
{
[self.view addSubview:_progressHUD];
}
[_progressHUD release];
_progressHUD.labelText = #"Loading...";
[_progressHUD show:YES];
}
And viewDidUnload:
- (void)viewDidUnload
{
[_photoViewController release];
[super viewDidUnload];
}
The viewControllers view loading mechanism after a memory warning is supposed to be transparent to the developer. you shouldn't have to do a thing to re-create the view.
For VCs loaded using nib, the system will re-create the view and viewDidLoad will be called.
For VCs loaded programatically loadView will be called again.
and the whole cycle repeats until viewDidAppear: and you see the view again.
USE CASE:
UITabBarController (2 tabs assumed)
User on Tab 0 >> Goes to Tab 1 >> Triggers memory warning >> All active VCs on UITabbarController receive memory warning >> UITabBarController will unload view of Tab0 >> Tab0 receives viewDidUnload:
When user switches back to Tab 0 its view will be created from scratch beginning from loadView OR viewDidLoad as I said.
If you are not receiving these events then your viewController hierarchy is messed up. Maybe you just added some VCs view as subView to something OR maybe your VC is not connected to window either directly OR through some container controller (UINavigation, UITabBarController etc) OR maybe you tried rolling up you own containerController and messed up.
Try understand the UIViewController lifecycle from loadView to viewDidUnload and dealloc. Its awesome. It will help a lot in writing good code and design of your apps.
I have a large hierarchy of view/viewcontrollers.
In the main controller I have the following code where aViewController is a member of MyClass:
#implementation MyClass
...
- (void) viewDidLoad
{
[self.view addSubview:aViewController_.view];
[aViewController_ setDataSource:self];
[aViewController_ setDelegate:self];
}
- (void)dealloc
{
//[aViewController_.view removeFromSuperview]; // All ok when this is added
[aViewController_ release];
[super dealloc];
}
...
#end
When running this, I see that aViewController is never released - retain count remains 1 at the end.
If howeevr I add [aViewController_.view removeFromSuperview]; to dealloc the everything works fine.
Why is this? Shouldn't [super dealloc] take care of the release of the view? Does it matter that the view is being released after the controller?
I have tried to reproduce with a simple test application without any luck.
This is adding your view to be a subview of aViewController_.view.
[self.view addSubview:aViewController_.view];
aViewController_.view is retaining the view so when you release your main controller the view does not get deallocated that is correct.
You need to remove the view from the superview before you deallocate your "main controller".
The "main controller" will be gone when you release it but the super view still has retention of the subview.
You can do this somewhere in the aViewController_ when your finished with the view before you release the controller that owns the view.
Its hard to say without seeing all your code.
Just remember that when you add the view to another view that the super view retains the view until it is removed.
I am having difficulty geting a very simple view to display. This view has a custom view controller that is manages by a switching view controller. The XIB has one UIViewController component on it with its Image property set. The view controller is as follows:
InstructionsViewController.h
#import <UIKit/UIKit.h>
#interface InstructionsViewController : UIViewController {
}
#end
InstructionsViewController.m
#import "InstructionsViewController.h"
#implementation InstructionsViewController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
- (void)dealloc {
[super dealloc];
}
#end
I have also set the class property for the XIB's File's Owner to InstructionsViewController, and Ctrl+Dragged File's Owner to the View icon and selected View from the popup menu.
The code to display the view is:
- (void) showInstructions
{
//Lazy load the instruction view.
if (self.instructionsViewController == nil)
{
InstructionsViewController *viewController = [[InstructionsViewController alloc]
initWithNibName:#"InstructionsView"
bundle:nil];
self.instructionsViewController = viewController;
[viewController release];
}
[self.view insertSubview:viewController.view atIndex:0];
}
My view controller that animates different views when they are switched, has no problems loading and displaying three other views. It just doesn't like this one.
I'm sure I've missed something simple, but for the life of me I can't get it to work for some reason. Does anyone have any pointers?
Thanks,
Steve
I just had the same thing. Ended up deleting the UIImageView, placing a new one then relinked and it worked. Seems like some corruption somewhere.
Not even really sure how this is compiling. You are inserting the subview outside of your nil check, where viewController is out of scope.
You probably want to do
[self.view insertSubview:self.instructionsViewController.view atIndex:0];
Have you verified that showInstructions is being called by setting a breakpoint there? One other thing to check is that you are inserting the Instructions view at the bottom of your z-order, so it will be behind all other items. Try using:
[self.view addSubview:self.instructionsViewController.view];
This will add it to the top of the z-order. If that doesn't work, also try:
[self.view setNeedsLayout];
and/or:
[self.instructionsViewController.view setNeedsLayout];
Ok, I've finally solved it!
The problem was something in XCode or Interface Builder was not agreeing with the PNG file I specified for the Image View control in IB. I tried re-naming, and re-specifying, etc. to no avail.
I finally had to delete the graphic and re-copy it from it's source location. Then I re-specified it in Image View, build and ran. Now it works.
Everything is good in the world again.
Thanks to those who took the time to read and offer help. I appreciate it very much!
Steve