On Apr 4, 2015, at 00:07 , Markus Spoettl <ms_li...@shiftoption.com> 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 (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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

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

Reply via email to