On Oct 21, 2009, at 18:38, Ben Haller wrote:

I don't understand why you think you can't invoke [super openUntitledDocumentAndDisplay: displayDocument error: outError] immediately after displaying your initial-state-choosing dialog. Because of the need to pass a customized type string? In that case, stash the type in a subclass instance variable and override defaultType to return it. Alternately, put the initial state in a global variable and consult that variable in your NSDocument subclass initWithType: -- that's a bit ugly, but it's safe enough because this all needs to be done on the main thread anyway.

Both of those options seem more than a little bit ugly to me. They depend quite intimately on the behavior of the NSDocument architecture, and the ordering of events. If, for example, NSDocumentController decided to make a different new document in the middle of this process, for whatever reason (and processing multiple documents for opening or printing makes that seem not implausible), both of these workarounds could backfire.

1. Yes, there's a defect in the NSDocumentController design which makes it awkward to pass an initial state to a new document without having to re-implement everything that NSDocumentController does. Awkward but not impossible or even difficult. So let's just get over it and move on.

2. My second suggestion *in no way* depends on knowing what any method of NSDocumentController actually does, except that I consulted the documentation for 'newDocument:' to guide me in choosing which method to override. If that bugs you, override 'newDocument:' too, to make it do what the documentation says it currently does, and you're future- proofed until and unless 'openUntitledDocumentAndDisplay:error:' is deprecated.

My first suggestion depends on knowing that the type passed to the new document instance will be provided by 'defaultType'. It's conceivable but extremely unlikely that this is ever going to change, but if that bothers you, use the second suggestion.

Your existing code is, in a sense, more dependent on the current implementation details of NSDocumentController, because you're trying to do what the documentation says that NSDocumentController does.

3. The only ways my second suggestion (and, for all practical purposes, my first suggestion) could fail are (a) if documents were being created on multiple threads, which can't happen because NSDocumentController isn't thread safe, or (b) if 'openUntitledDocumentAndDisplay:error:' could possibly get called recursively, which it doesn't. If you're worried about that, then go ahead and use your current implementation, which is perfectly viable even if it makes you uncomfortable.

Well, two points in response to that. One, the NSError documentation says:

In general, a method should signal an error condition by—for example— returning NO or nil rather than by the simple presence of an error object. The method can then optionally return an NSError object by reference, in order to further describe the error.

  So if the NSError is required, that seems questionable.
More importantly, however, if I do make an NSError object and pass it back, then the NSDocument architecture displays an error panel to the user that says "No document could be created"! Since the user has just clicked Cancel, that is obviously wrong. If I select New in Interface Builder, then cancel out of it, I don't get a panel warning me that a new document could not be created.

Is anybody at Apple reading this thread? I'd really like to get advice from somebody who knows how this architecture was intended to be used. I can't imagine that such a simple, common usage pattern falls through cracks in the design. I must simply be using the framework incorrectly. Anyone who has actually implemented a document like this care to comment?

Huh? You *are* getting advice from somebody who knows how this architecture is intended to be used, both from having implemented "a document like this", and from having carefully absorbed *extensive* discussions on this list of how the NSError** output parameter is intended to be used.

Read this:

        
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/ErrorHandlingCocoa/CreateCustomizeNSError/CreateCustomizeNSError.html#//apple_ref/doc/uid/TP40001806-CH204-BAJIIGCC

and note particularly:

Note: Cocoa methods that indirectly return error objects in the Cocoa error domain are guaranteed to return such objects if the method indicates failure by directly returning nil or NO. With such methods, you should always check if the return value is nil or NO before attempting to do anything with the NSError object.

NSDocumentController methods play by these specific rules, so your overrides must do so too. Returning the "user cancelled" error is a special-case refinement of the technique that permits the (ultimate) suppression of the error alert. (The same technique is useful in cases where there really is an error but you want to display the alert yourself, but you want to prevent the NSDocumentController from complaining a second time.) It's not really well documented, but -- I hope you noticed -- you got the answer for free just by asking the question.


_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to