> On Mar 9, 2016, at 1:00 PM, Quincey Morris 
> <[email protected]> wrote:
> 
> On Mar 9, 2016, at 05:59 , Bill Cheeseman <[email protected]> wrote:
>> 
>> But the main thrust of my question was whether this is a safe and sensible 
>> way to crossreference other storyboard scenes -- at least when 
>> prepareForSegue(_:sender:) isn't available, as it isn't here. Having thought 
>> about it for a while now, I guess it is a sensible approach. It has less to 
>> do with storyboards than with the longstanding fact that NSApplication has a 
>> 'mainwindow' property and NSWindow has a 'contentViewController' property.
> 
> I think you ended up solving the “wrong” problem. The lazy initialization is 
> unnecessary, and so is the mucking about with optionals, because the window 
> controller and window both exist by the time applicationDidFinishLaunching is 
> invoked. The window isn’t main yet, but that’s the wrong place to look for 
> it: apart from anything else, your proposed code is fragile because if your 
> app ever has other windows that become main, even temporarily, you 
> temporarily lose the ability to find your shoebox window.

That sort of issue is talked about in a footnote at the end of the very recent 
Tech Q&A QA1871, which suggests using a view controller's representedObject 
instead of a window for Cocoa bindings in a storyboard for the same reason. But 
I'm reserving representedObject for my model object, as the Q&A suggests.

It hadn't occurred to me that the issue might not be the existence of the 
window but only whether it had become the mainWindow by the time 
applicationDidFinishLaunching(_:) is called. But by using lazy initialization I 
no longer have to set this instance variable's value in 
applicationDidFinishLaunching(_:). I don't actually use the reference to the 
content view controller until I know it is safe (I use it in a NSMenuDelegate 
method when the user opens a menu in the main menu bar). But that is 
happenstance, not safe coding. I added 'guard', and then Optionals as you 
suggested, out of a sense that Swift encourages this sort of thing for safety's 
sake.

> (I’m talking about window controllers because, once you have a reference to 
> the window controller, it’s easy to find the content view controller.)
> 
> The storyboard is automatically instantiated in NSApplicationMain. (When the 
> instantiation happens, there must be a strong reference to the WC stored 
> somewhere, otherwise the WC would be deallocated, but it looks like you don’t 
> get access to that reference in Swift projects. In Obj-C, you used to get a 
> templated property on the app delegate.) What you can do instead is subclass 
> NSWindowController, and use ‘windowDidLoad’ as your opportunity to save your 
> own strong reference to the WC. (In Swift, I think I’d make it a static 
> property of the WC class. This also lets you check that nothing creates a 
> second main window.)

Using windowDidLoad() is a good idea. It is triggered at exactly the right time 
for my purposes. I already find myself setting other instance variables back up 
the storyboard controller hierarchy in similar circumstances. But don't I still 
need to use optionals if I declare the window controller or content view 
controller instance variable in AppDelegate but don't set it until later in the 
window controller's windowDidLoad() method? I am still at risk of using the 
instance variable before its value has been set. (I could solve that problem, 
or rather localize it, by not making it an instance variable but instead a 
local variable where I actually use it, but the whole point of my current 
exercise is to have a chain of storyboard scene cross references.)

You say you would make it a static property of the window controller class. But 
I need to refer to it in AppDelegate. So, I guess you're saying I can refer to 
a static class variable from anywhere. This is what the Swift language guide 
refers to as a "type property," right? I see from the guide that I can refer to 
it from any class in my application as a property of the type as opposed to a 
property of an instance. It strikes me that this is exactly what I need. And it 
feels so much more appropriate to place the reference in the window controller 
itself, instead of in AppDelegate. (So, a Swift "singleton" class can have a 
type property that refers to its own sole instance? And that type property is 
accessible everywhere in the application? Weird. And amazingly convenient. So 
much still to learn about Swift!)

> If you find this inconvenient or distasteful, your other alternative is to 
> take the “isInitialController” status off the WC in the storyboard, and 
> instantiate the WC yourself in (say) applicationDidFinishLaunching. Or, 
> almost the same thing, move the window and view scenes out of the main 
> storyboard into a separate storyboard. 

It is uncomfortable, but storyboards are making lots of things uncomfortable -- 
or, rather, they are forcing me to do a lot of rethinking of old principles. I 
find myself spending a lot of time wondering which scene to use for code that 
in the old days used to get thrown into a single, massive window controller 
class where worries like this did not intrude. In this project, I am making 
heavy use of view controllers to break my code down into much smaller pieces, 
which storyboards encourage. In addition, having a lot of scenes in a single 
storyboard, as opposed to multiple nib files, encourages one to think that code 
can be put anywhere. That's why I'm inventing all the ways I can think of to 
create workable cross references between scenes. And Apple encourages that in 
the WWDC 2014 video by repeating way too many times that you really have to 
implement prepareForSegue(_:sender:) all over the place if you use storyboards. 
I guess it has always been considered more acceptable for view controllers to 
cross reference one another, as opposed to model classes and view classes that 
are supposed to be as reusable as possible.

I am aware that I can turn to loading the storyboard myself in code. My 
instinct is always to take advantage of anything that Apple makes automatic, 
until I have really exhausted all possible attempts to find a way to do that.

Thanks again for your help.

-- 

Bill Cheeseman - [email protected]

_______________________________________________

Cocoa-dev mailing list ([email protected])

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [email protected]

Reply via email to