Managing External Subviews and Layout

I'm writing a Mac OS app in Objective-C. The mainWindowController has a vertical NSSplitView in the application's window. This split view is in the mainWindowController's nib file. In mainWindowController's viewDidLoad, I instantiate two child controllers--call them A and B. A and B each have their own nib that contains nothing but an NSView. Later, A and B will instantiate children objects in their own viewDidLoad, giving a hierarchy.

As you may expect, A's view and B's view form the left and right panes of the mainWindowController's split view. Herein lies the problem.

When I instantiate each object in mainWindowController, I don't know if their views actually exist after the alloc/init call. In fact, I believe I should assume they do not yet exist. mainWindowController must add A and B to its split view and then create the autolayout constraints for both A and B, since they are relative to each other.

So, in mainWindowController, how can I know when A and B have loaded their views so that I can add them to the split view and setup the proper autolayout constraints? I can think of some ways to implement this, but each solution is uglier than the last. What is the best practice here?

As I mentioned, A and B will be creating their own subviews, etc, so this is a general problem I will have to deal with in this app.

I appreciate any input!

Accepted Reply

when [[alloc] initWithNibName] returned, it was not guaranteed that those nibs would be loaded

I do think it is loaded when initWithNibName returns.

As for avoiding an extra view, I do not see this as a problem. There are so many objects allocated by the system, that even if you have hundreds of view, just an extra view each time will not make a difference.
There are probably many other places in code more important top focus on if you need to optimize.

In anycase, good to read it works.
You should close the thread now.

Replies

Why don't you create the splitView in IB ? With 2 subviews, which are A and B.

Then in the viewDidLoad of the splitView or even in applicationDidFinishLaunching, you can insert any object like this (to insert a dummy button in the first view (A for you if I understand well)):

Code Block
let button = NSButton(title: "New", target: self, action: nil)
button.frame = CGRect(x: 20, y: 120, width: 100, height: 20)
(self.splitView.subviews[0] as! NSScrollView).contentView.addSubview(button)


With the same pattern, you can instantiate viewA and viewB and add them to the corresponding subview of the splitView.

For the constraints, you can define them in the nib or programmatically (you should subclass NSScrollView for A and B to connect to the IBOutlets in that case).

This is Swift, but you should have no problem to write it in objC.

If that answers your question, don't forget to close the thread by marking this answer as correct.
Otherwise, please explain the remaining problem.
Yes, I could add child views to the NSSplitView which is already in the MainWindowController nib. In fact, I did that to start with and that eliminates the autolayout issue. With that implementation, I setup the autolayout in IB, just as you suggested, then instantiated A and B and added them as children to the views that already existed. And it works fine, of course. The reason I chose to not do it that way is to remove those extra unused views for efficiency. This is (getting to be) a rather complex app and I wanted to avoid having extra views lying around that don't really do anything.

All that aside, I think my initial assumption was incorrect. The problem I thought I was going to run into is essentially this: SplitView is loaded from its nib and MainWindowController.viewDidLoad gets called. In viewDidLoad, I do a = [[A alloc] initWithNibName:]; b = [[B alloc] initWithNibName:]; I thought that when [[alloc] initWithNibName] returned, it was not guaranteed that those nibs would be loaded yet and so the views in them wouldn't be guaranteed to exist yet. If that were true, there would be no A.view or B.view to add to the SplitView or do autolayout with.

Last night, I went ahead and implemented it anyway assuming that the nib would be loaded and the view would exist after the return of [alloc] initWithNibName:] and it works fine. I think I incorrectly inferred A.view and B.view wouldn't be guaranteed to exist yet, because of the existence of viewDidLoad.

Or, was my initial assumption correct and I'm just getting lucky that A.view and B.view happen to exist immediately up return from [alloc] initWithNibName:]?

when [[alloc] initWithNibName] returned, it was not guaranteed that those nibs would be loaded

I do think it is loaded when initWithNibName returns.

As for avoiding an extra view, I do not see this as a problem. There are so many objects allocated by the system, that even if you have hundreds of view, just an extra view each time will not make a difference.
There are probably many other places in code more important top focus on if you need to optimize.

In anycase, good to read it works.
You should close the thread now.