Re: How to run a panel that customizes a new NSDocument
Re: How to run a panel that customizes a new NSDocument
- Subject: Re: How to run a panel that customizes a new NSDocument
- From: Quincey Morris <email@hidden>
- Date: Wed, 21 Oct 2009 23:24:22 -0700
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 (email@hidden)
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:
This email sent to email@hidden