View is null in viewDidLoad - view

I created UITabBarController with each tab contain UINavigationController and set rootviewcontroller in this UINavigationController, all of this is done in interface builder. In viewDidLoad I try to get frame size from view, but when I reference view it return null. Have anyone experienced this before.
All IBoutlet are properly connected.

viewDidLoad returning a nil view if the view is connected in your .xib could mean:
For programmatic initialisation (custom controllers):
You forgot to call initWithNibName:bundle: on the view controller class altogether (you may have called init or something instead).
You've overridden the loadView method in your view controller class, but it doesn't set the view.
For all controllers:
An outlet connection hasn't been made correctly.
You have accidentally released the view or view controller before showing it.
The nibName parameter was not properly specified when initialising the view (the nib could not be found or one without a view was found.. though this should also throw an exception).
There wasn't enough memory to allocate the view (the app would likely have been terminated by that point though).
I'd recommend you try doing frame size calculations in viewWillAppear: instead and see if the view is still nil at that point.

Related

Unable to change delegate on NSSplitView

I have a storyboard that contains a main window (with a corresponding MainWindowController class), and a main view (an NSSplitViewController, with corresponding MainViewController class). For certain functionality I am attempting to set the delegate of the NSSplitView contained in the view to the MainWindowController class.
Without any IB linkage, the NSSplitView delegate is already set to the MainViewController at application launch. I am able to get a reference to the MainWindowController, but when I attempt to set the delegate to the window controller (which does implement NSSplitViewDelegate), I am getting the following:
*** Assertion failure in -[NSSplitView setDelegate:], /Library/Caches/com.apple.xbs/Sources/AppKit/AppKit-1404.34/AppKit.subproj/NSSplitView.m:600
This also happens if I attempt to set the delegate to nil.
Does anyone know why this might be so, whether there are restrictions on setting delegates, and if there is a way to use IB to set the delegate of an item in a view to another Controller?
Thanks.
I don't have a reference for this but I'm pretty sure the split view and the split view controller aren't meant to be separated. Fortunately, NSSplitViewController mirrors the delegate methods, giving you a chance to intervene. There should therefore be no reason to change the split view's delegate.

NSTableView loads data, but cannot reload

I've got two NSTableViews set up, being populated by one nstableviewdatasource and delegate. Both tableviews receive data when first loaded without issue, however they refuse to reload data. Both tableview datasource and delegates are connected to my tableviewcontroller class object in the xib.
I've confirmed that my method, which sets new data to the array I use to populate the tableviews, actually receives the changed data. This method is the only way I populate the array that the datasource delegate methods use. It is being reloaded from the main thread:
myArray = [classThatHoldsNewVariables.array mutableCopy];
[self.myTableView reloadData];
-numberOfRowsInTableView does not get called with reloadData. It only gets called on app launch.
I've tried manually setting the datasource and delegate methods in code, without any success. I've tried so many different ways of getting reloadData to work, and nothing happens.
Help :(
EDIT:
I fixed the problem. It was an instance issue, where I was alloc init-ing my nstableviewdatasource from another class to reload the data. Init does not load the instance used by the nib, so it's reloading another instance of my tableview, which isn't shown to the user. I solved this by implementing nsnotifications in my tableviewcontroller class instead.
Sounds like myTableView is nil, thus sending it the reloadData method isn't doing anything.
If it's an outlet, make sure it's connected in the xib. If not, note that a UITableViewController's table view is, by default, referenced by the tableView property, not myTableView.
I fixed the problem. It was an instance issue, where I was alloc init-ing my nstableviewdatasource from another class to reload the data. Init does not load the instance used by the nib, so it's reloading another instance of my tableview, which isn't shown to the user. I solved this by implementing nsnotifications in my tableviewcontroller class instead.

Subviews of a NSCollectionViewItem's view are always nil

I have a very basic setup with a NSCollectionView. I have a subclassed NSCollectionViewItem which is used as the itemPrototype for the collection view. The collection view item has a view.
Using Interface Builder, I added an NSImageView to the collection view item's view and connected an IBOutlet to the instance of my collection view item subclass. The property for the IBOutlet is uses retain for its memory management.
My goal is to hide or show this image view whenever the selection state for the collection view item changes. But within the setSelected: method my property for the image view is nil, even though I am 100% sure its outlet is connected, its property is set to retain and i have not unset or released the image view.
I had a similar issue with collection view items where an activity indicator added to the view was always nil too. Why does this happen and what do I need to do to fix it?
As far as I now, IBOutlets pointing to non-top level objects in nib/xib file should be defined (weak).
Are you sure you have changed the class of NSCollectionView item correctly?
When breaking in setSelected:, and doing a po self in the debugger console, are you seeing the name of your class?

initWithNibName either called twice or wrong xib loaded

I'm programming a Cocoa application and want the application to work as a kind of Wizard. So in the main window I have a Custom View that interacts with the user and changes from a sign in to a device activation screen as they step through the stages of the wizard. I have currently overridden the WizardViewController's awakeFromNib method:
- (void)awakeFromNib{
//If no redirect request save, add first view: ID Login
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *tokenRequest = [defaults objectForKey:#"redirectRequestToken"];
if (!tokenRequest){
SignInWithIDViewController *signInViewController = [[SignInWithIDViewController alloc] initWithNibName:#"SignInWithIDViewController" bundle:nil];
[wizardView addSubview:[signInViewController view]];
} else {
NSLog(#"Have already logged in.");
}
}
As is, initWithNibName in SignInIDViewController gets called twice, once explicitly by me, and again when the view is loaded (presumably through loadView). However, if I simply call init then initWithNib name is only called once, but the wrong xib file is loaded (of the DeviceActivationViewController class). I can't seem to figure out what I'm doing wrong, because the signInViewController should not be init twice, but I need the proper xib file in IB to display.
The only other method I have in this class currently that is not a user interface IBAction is the generated initWithNibName method plus an added NSLog statement.
I think that creating the objects in IB (the blue cubes), and instantiating them in code is the problem. If you've created objects for them in IB, then they will be instantiated in awakeFromNib, you shouldn't also call alloc init on them in code -- that will create a new instance.
I don't have a lot of experience with using view controllers in OSX, but it seems that you can't connect IBActions to the view controller (as file's owner). The way I made it work, was to subclass the custom view (that's created for you when you add a view controller), change the class of that view to your new subclass, and put the action methods in that class. It seems like this should be something that would be handled by the view controller, but I think it not working has something to do with the view controller not being in the responder chain in OSX (whereas I think it is in iOS).
After Edit: After a detour into memory management problems, I think I found the best way to do this. You can, and probably should (to comply with Apple's MVC paradigm) put the button methods in the view controller class rather than in the view as I said above. You actually can connect the IBActions to the view controller (as File's Owner), you just need to make sure that the view controller is retained when you instantiate it in code. To do this, you need to make signInViewController a property in whatever class you're instantiating the SignInViewController class in, and use "retain" in the property declaration. Then you don't need to (and shouldn't) create any of the blue cubes in IB.

SplitView in Storyboard, can't connect delegate

I have an iPad interface defined in a storyboard, with a SplitViewController. I want to set the delegate of the SplitViewController to point to the detail controller, but IB won't allow that connection to be made.
Putting an "object" object and changing the class to that of my detail controller makes the delegate point to a different instance of the detail controller than the one displayed.
My attempts to connect it manually (in didFinishLaunching) in the app delegate were fruitless, the delegate was still nil.
Changing the delegate to the AppDelegate and implementing the protocol there worked, but passing messages to the detail controller didn't work (even though I verified that I was referencing the same instance).
Nothing works. I can set self.splitViewController.delegate = self when detail view loads, and then it becomes the delegate with no problem. But I miss any delegate calls that happen before that point.
For context, I need to get the splitviewcontroller's delegate calls so that I can show a button in the detailview to show a popover, as is standard practice. Right now, if the app is launched in portrait, it has to be rotated to landscape and then back for the button to show.
I've done this with "normal" xibs with no issue. It seems to be a special case of the more general problem of not being allowed to connect outlets across scenes in a storyboard.
I have no idea why this worked this time and not the first 80 times, but I added this to my AppDelegate:
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
UINavigationController *navigationController = [splitViewController.viewControllers lastObject];
splitViewController.delegate = (id)navigationController.topViewController;

Resources