Re: Preventing Document from closing
Re: Preventing Document from closing
- Subject: Re: Preventing Document from closing
- From: Quincey Morris <email@hidden>
- Date: Sat, 04 Apr 2015 08:16:04 +0000
On Apr 4, 2015, at 00:07 , Markus Spoettl <email@hidden> wrote:
>
> and not as the documentation indicates
>
> document:shouldClose:contextInfo:
>
> Every time I try to make sense of this and the header comments, my head starts spinning.
It says that’s the *signature*, not the *selector*. The selector is the name of the method, which is passed as a parameter. The signature (at least in this context) is the number, type and order of the parameters.
However, to save your head, here’s some code that works, in a NSDocument subclass. plus some bonus code:
> - (void) canCloseDocumentWithDelegate: (id) delegate shouldCloseSelector: (SEL) shouldCloseSelector contextInfo: (void*) context
> {
> MyDocument* document = self;
>
> // If it's not OK to close the document now, the delegate's selector must still be invoked, with 'shouldClose' set to NO
>
> if (![self documentShouldClose]) // a MyDocument method
> {
> NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: shouldCloseSelector]];
> [invocation setTarget: delegate];
> [invocation setSelector: shouldCloseSelector];
> [invocation setArgument: &document atIndex: 2]; // document:
> BOOL shouldClose = NO;
> [invocation setArgument: &shouldClose atIndex: 3]; // shouldClose: NO
> [invocation setArgument: &context atIndex: 4]; // contextInfo:
> [invocation invoke];
> }
>
> // If it's OK to close the document, continue with the 'super' implementation of this method,
> // but substitute our own delegate and selector, so that we can invoke the 'willClose' method
>
> else
> {
> // Package up the original delegate's selector invocation, so that it can be called later
>
> NSInvocation* originalInvocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: shouldCloseSelector]];
> [originalInvocation setTarget: delegate];
> [originalInvocation setSelector: shouldCloseSelector];
> [originalInvocation setArgument: &document atIndex: 2]; // document:
> [originalInvocation setArgument: &context atIndex: 4]; // contextInfo:
>
> // Handle document closing normally, except that our own delegate will eventually be called
>
> [super canCloseDocumentWithDelegate: self shouldCloseSelector: @selector (thisDocument:shouldClose:contextInfo:) contextInfo: (__bridge_retained void*) originalInvocation];
> }
> }
>
> - (void) thisDocument:(NSDocument*) document shouldClose: (BOOL) shouldClose contextInfo: (void*) context
> {
> // Retrieve the original delegate invocation
>
> NSInvocation* originalInvocation = (__bridge_transfer NSInvocation*) context;
>
> // If closing has succeeded, let the document know
>
> if (shouldClose)
> [self willClose]; // a MyDocument method
>
> // Invoke the original delegate's selector with the appropriate 'shouldClose' value
>
> [originalInvocation setArgument: &shouldClose atIndex: 3];
> [originalInvocation invoke];
> }
The first branch of the ‘if’ statement is the code you want, that prevents the document from closing. Note that it doesn’t involve a separate method. Rather, it just invokes the supplied selector but changes one of the parameters to NO.
The else branch is the code you would use if you wanted to have to document do something before actually closing the document. In my case, I wanted to invoke a ‘willClose’ method first. The reason this part is so much more complicated is that it hasn’t been determined yet whether the document *will* close — that doesn’t happen until the supplied selector is invoked. So, my own method’s selector replaces the supplied selector in the ‘super’ invocation, and my method invokes the originally supplies selector when it’s done messing around.
Hope that makes sense. It *is* a little confusing. :)
P.S. This would be easier to follow if you could use ‘performSelector:’ instead, but there’s no form of it that takes non-objects as parameters. You have to fall back to NSInvocation.
_______________________________________________
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