"contentSizeForViewInPopover" - what does this do? - ios

This is both a question, and a solution.
I recently added a very simple UIViewController with a .xib to my iPad application, containing just a UIDatePicker and a UILabel, which I wish to display as a popup in my iPad app.
I added all of the relevant code to display this .xib as a popup. There were no errors or warnings, my UIViewController class was set as the "Class" for this .xib, and both controls showed that they were linked to the IBOutlets in this particular file.
But, when I ran the app, the popup would appear perfectly well, but if I tried to access anything to do with these two controls, nothing would happen.
So, for example, the following code attempted to set the label's text, to change the UIDatePicker's mode... and nothing would happen. I tried breakpoints, the code WAS being run, the controls did have a value (they weren't nil) but this code wouldn't do anything. The UILabel's text wouldn't be changed, the DatePicker would continue to be in "Date & Time" mode, etc.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
[self.datePicker addTarget:self action:#selector(LabelChange:) forControlEvents:UIControlEventValueChanged];
self.lblQuestion.text = #"Is this working...?";
self.datePicker.datePickerMode = UIDatePickerModeDate;
self.datePicker.date = [NSDate date];
}
return self;
}
Eventually - eventually - I added one line of code, to set the "contentSizeForViewInPopover":
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Without this line of code, the code-behind doesn't communicate
// with the controls in this .xib
self.contentSizeForViewInPopover = self.view.bounds.size;
// ... etc ...
...and suddenly, it worked beautifully.
So, my question is.. why ?!
What the heck does this one line of code do, which suddenly makes it so I can set my UILabel's text, and can talk to the UIDatePicker control...?
I'm very used to the quirks and crashes with XCode, but I'm baffled by why this suddenly made my code start to work. I'm relieved that this quirk "only" wasted a couple of hours of my life... and would like to understand the reason behind it.
Btw, this is with XCode 4.6.3, running on an iOS 6.1 SDK app for an iPad.

The outlets are connected when the nib is loaded. The nib is loaded when you access the controllers's view for the first time.
In other words, in your initializer all your outlets are nil. However, if you call self.view, your view gets loaded and outlets are connected. contentSizeForViewInPopover or bounds.size is irrelevant.
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.view; //this is enough
...
This is why you shouldn't put such code into initializer but into viewDidLoad instead.
- (void)viewDidLoad {
[self.datePicker addTarget:self
action:#selector(LabelChange:)
forControlEvents:UIControlEventValueChanged];
self.lblQuestion.text = #"Is this working...?";
self.datePicker.datePickerMode = UIDatePickerModeDate;
self.datePicker.date = [NSDate date];
}

Related

UITabBarController tabbar item shows only when selected

My project is in Xcode 5.0.2 and since I've upgraded to OS X 10.10 I can't use Xcode 5.0.2 now and I need to use Xcode 6 but my problem is my tabbar items in xib file only shows when they're selected(Once selected the image with load and will not hide when unselected).here's the screenshot of it on first load.
Note: I'm using an old UITabBarController usign xib
The solution is only [self setNeedsToDisplay] :D My layout is not updating. Thanks for the help guys :D
In ViewController of every tab add the below code with there respective title and image.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
self.tabBarItem.title = #"Dashboard";
self.tabBarItem.image = [[UIImage imageNamed:#"dashBoard"]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal ];
self.tabBarItem.selectedImage=[[UIImage imageNamed:#"dashBoardSelect"]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
}
return self;
}

Setting delegate to MKMapView

I am new to iOS programming. I have created ViewController with MKMapView element, and I wanted to set delegate [mapView setDelegate:self]
First I done it in method initWithNibName:bundle: like:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
[[self map] setDelegate:self]];
UITabBarItem *item = [[UITabBarItem alloc] init];
[item setTitle:#"Map"];
[self setTabBarItem:item];
}
return self;
}
In this case MKMapView did not send me any messages, but when I placed setting delegate message to viewDidLoad method, it worked fine.
Could someone explain me why it was not working when setting delegate message was in initWithNibName:bundle?
Views do not get loaded in initWithNibName, it just initializes your viewcontroller class and load the xib file which contains your view details.
When viewcontroller calls viewDidLoad, you will have all your view objects allocated and initialized.
In your case, when you setDelegate in initWithNibname, you are calling it on a nil value, so nothing get set, but in viewDidLoad mapView is allocated and initialized, so it works fine.
For a deeper insight refer:
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html
Beautiful explanation here: What is the process of a UIViewController birth (which method follows which)?
Looking to understand the iOS UIViewController lifecycle
http://thejoeconwayblog.wordpress.com/2012/10/04/view-controller-lifecycle-in-ios-6/
This line is your problem:
[self map]
In initWithNibName the map is not yet initialized and it returns nil.
In viewDidLoad the map is already initialized.

proper way to set badge value on uninstantiated view controller?

I have 2 view controllers in a tab bar controller. My 2nd Nav Controller wants to set a badge value.
This controller is not loaded when the app starts, so the badge does not show. If I go over to that tab, the badge is properly updated.
this snippet runs when the tab's View Controller loads/reloads/updates/etc...
[self.navigationController.tabBarItem setBadgeValue:[NSString stringWithFormat:#"%u",[self.photos count]]];
Is the correct way to do this: Override the Nav Controller with a custom class and put the badge value in at that level? It seems like that is where I should put this info, but I haven't found a definite answer.
When the TabBarController is loaded, all of it's contained initial viewControllers are initialised. But their views are not loaded until you navigate to the respective tab item. So you can't execute code at this point in any of the view-loading methods (viewDidLoad etc). However you can execute code by overriding one of the initialisation methods.
If using storyboards the process of unarchiving the viewController triggers this method when the NIB has loaded:
- (void) awakeFromNib
{
}
If not using Storyboards, this initialiser is called prior to NIB loading:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
In either case you can override these methods to execute some code...
- (void) awakeFromNib
[super awakeFromNib];
[self.navigationController.tabBarItem
setBadgeValue:[NSString stringWithFormat:#"badgeValue"]]];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
[self.navigationController.tabBarItem
setBadgeValue:[NSString stringWithFormat:#"badgeValue"]]];
}
return self;
}
However you will need to take care where you are getting your data from. At this point self.photos may be uninitialised for example. If the data for this is coming out of userdefaults, you should be able to read those in here and set your badge accordingly.

UIViewController viewDidLoad called before init method is complete

I have a view controller that initializes two other view controllers. The view for one controller wasn't showing, and I tracked the problem to the instance being nil when it's added to the superview.
Here is the code. viewDidLoad is being called before the favoritesTableVC is initialized. I can see this by placing breakpoints in the initialization methods of the resultsTableVC and favoritesTableVC view controllers.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
resultsTableVC = [[[ResultsTableVC alloc] initWithController:self andTableView:nil] retain];
favoritesTableVC = [[[FavoritesTableVC alloc] initWithFrame:CGRectMake(0, 10, self.view.frame.size.width, defaultFavoritesTableHeight) andController:self] retain];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view addSubview:resultsTableVC.view];
[resultsTableVC release];
[self.view addSubview:favoritesTableVC.view];
[favoritesTableVC release];
}
Here is the order the methods are being called:
allResults init
resultsTableVC init
allResults viewDidLoad
addSubview allResultsVC
addSubview favoritesResultsVC
favoritesResultsVC init
This is a single thread, so I don't understand how viewDidLoad can be called before init is complete.
-[ResultsTableVC initWithController:andTableView:] is probably referencing allResults.view.
This would force the allResults controller to load its view (which then of course causes viewDidLoad to fire). All of this happens synchronously, before you actually return from initWithController:andTableView:
I'm taking a guess, but could you try this :
favoritesTableVC = [[[FavoritesTableVC alloc] initWithFrame:CGRectMake(0, 10, SOME_HARD_CODED_INT, SOME_HARD_CODED_INT) andController:self] retain];
And see if you get the same result.
My guess is that self.view is pointing to nil at that time.
But that wouldn't explain why the init is call after... but no harm in trying.
(I haven't tested it)

Please explain me why I can't set this UIButton hidden

Please explain me why:
[inboxB setHidden:YES];
NSLog(#"is hidden ? %i", [inboxB isHidden]); // gives 0
inboxB is an outlet. I'm inside this initializer:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
...
thanks
Most likely inboxB is nil at the time when you set it.
Messages to nil fail silently and (almost) always return 0. So your code would look like:
[nil setHidden:YES]; // Does nothing
[nil isHidden]; // Returns 0 or 'NO'
If it's an outlet, check to make sure you've connected it to something.
I've run into this problem a few times with getters, I believe you need to access the property directly which calls isHidden which I believe is a private method.
Try:
indoxB.hidden;

Resources