NSInvocation为傻瓜?
NSInvocation
究竟如何工作? 有一个很好的介绍吗?
我特别在理解下面的代码(来自Cocoa Programming for Mac OS X,3rd Edition )是如何工作的,但是也可以独立于教程示例应用这些概念。 代码:
- (void)insertObject:(Person *)p inEmployeesAtIndex:(int)index { NSLog(@"adding %@ to %@", p, employees); // Add inverse of this operation to undo stack NSUndoManager *undo = [self undoManager]; [[undo prepareWithInvocationTarget:self] removeObjectFromEmployeesAtIndex:index]; if (![undo isUndoing]) [undo setActionName:@"Insert Person"]; // Finally, add person to the array [employees insertObject:p atIndex:index]; } - (void)removeObjectFromEmployeesAtIndex:(int)index { Person *p = [employees objectAtIndex:index]; NSLog(@"removing %@ from %@", p, employees); // Add inverse of this operation to undo stack NSUndoManager *undo = [self undoManager]; [[undo prepareWithInvocationTarget:self] insertObject:p inEmployeesAtIndex:index]; if (![undo isUndoing]) [undo setActionName:@"Delete Person"]; // Finally, remove person from array [employees removeObjectAtIndex:index]; }
我得到了它想要做的事情。 (顺便说一下, employees
是自定义Person
类的NSArray
。)
作为一个.NET人,我尝试将不熟悉的Obj-C和Cocoa概念联系到大致类似的.NET概念。 这是类似于.NET的委托概念,但无types?
这本书不是100%清楚的,所以我正在寻找来自真正的cocoa/ Obj-C专家的补充,同样的目标是我理解简单(示例)下面的基本概念。 我真的希望能够独立应用知识,直到第九章,我毫不费力地做到这一点。 但现在 …
提前致谢!
根据苹果的NSInvocation类参考 :
NSInvocation
是一个呈现静态的Objective-C消息,也就是说,它是一个变成对象的动作。
而且,再详细一点 :
消息的概念是客观哲学的核心。 任何时候你调用一个方法,或者访问某个对象的variables,你都会发送一条消息。 NSInvocation
派上用场,当你想发送一个消息到一个对象在不同的时间点,或者多次发送相同的消息。 NSInvocation
允许你描述你要发送的消息,然后调用它(实际上发送给目标对象)。
例如,假设您想要将一个string添加到数组中。 您通常会发送addObject:
消息,如下所示:
[myArray addObject:myString];
现在,假设您想在其他时间点使用NSInvocation
发送此消息:
首先,你需要准备一个NSInvocation
对象来与NSMutableArray
的addObject:
selector一起使用:
NSMethodSignature * mySignature = [NSMutableArray instanceMethodSignatureForSelector:@selector(addObject:)]; NSInvocation * myInvocation = [NSInvocation invocationWithMethodSignature:mySignature];
接下来,您将指定将消息发送到哪个对象:
[myInvocation setTarget:myArray];
指定您希望发送给该对象的消息:
[myInvocation setSelector:@selector(addObject:)];
并填写该方法的任何参数:
[myInvocation setArgument:&myString atIndex:2];
请注意,对象参数必须通过指针传递。 感谢Ryan McCuaig指出了这一点,请参阅Apple的文档了解更多细节。
在这一点上, myInvocation
是一个完整的对象,描述了一个可以发送的消息。 要实际发送消息,您可以调用:
[myInvocation invoke];
这最后一步将导致消息被发送,实质上执行[myArray addObject:myString];
。
想想它就像发送电子邮件。 你打开一个新的电子邮件( NSInvocation
对象),填写你想要发送的人(对象)的地址,为收件人键入一个消息(指定一个selector
和参数),然后点击“发送” (调用invoke
)。
有关更多信息,请参阅使用NSInvocation 。 如果上述不起作用,请参阅使用NSInvocation 。
NSUndoManager
使用NSInvocation
对象,以便它可以反转命令。 从本质上讲,你在做的是创build一个NSInvocation
对象来说:“嘿,如果你想撤消我刚刚做的,用这些参数发送这个消息到该对象。 您将NSInvocation
对象赋予NSUndoManager
,并将该对象添加到可NSUndoManager
操作的数组中。 如果用户调用“Undo”, NSUndoManager
只是查找数组中最近的操作,并调用存储的NSInvocation
对象来执行必要的操作。
有关更多详细信息,请参阅注册撤消操作 。
下面是一个简单的NSInvocation的例子:
- (void)hello:(NSString *)hello world:(NSString *)world { NSLog(@"%@ %@!", hello, world); NSMethodSignature *signature = [self methodSignatureForSelector:_cmd]; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; [invocation setTarget:self]; // index 0 (hidden) [invocation setSelector:_cmd]; // index 1 (hidden) [invocation setArgument:&hello atIndex:2]; // index 2 [invocation setArgument:&world atIndex:3]; // index 3 // NSTimer's always retain invocation arguments due to their firing delay. Release will occur when the timer invalidates itself. [NSTimer scheduledTimerWithTimeInterval:1 invocation:invocation repeats:NO]; }
当被叫 – [self hello:@"Hello" world:@"world"];
– 该方法将:
- 打印“Hello world!”
- 为自己创build一个NSMethodSignature。
- 创build并填充一个NSInvocation,调用它自己。
- 将NSInvocation传递给NSTimer
- 定时器将在(大约)1秒钟内触发,导致方法再次以其原始参数被调用。
- 重复。
最后,你会得到像这样的打印输出:
2010-07-11 17:48:45.262 Your App[2523:a0f] Hello world! 2010-07-11 17:48:46.266 Your App[2523:a0f] Hello world! 2010-07-11 17:48:47.266 Your App[2523:a0f] Hello world! 2010-07-11 17:48:48.267 Your App[2523:a0f] Hello world! 2010-07-11 17:48:49.268 Your App[2523:a0f] Hello world! 2010-07-11 17:48:50.268 Your App[2523:a0f] Hello world! 2010-07-11 17:48:51.269 Your App[2523:a0f] Hello world! ...
当然,目标对象self
必须继续存在,以便NSTimer将NSInvocation发送给它。 例如,一个Singleton对象,或者一个在应用程序期间存在的AppDelegate。
更新:
如上所述,当您将NSInvocation作为parameter passing给NSTimer时,NSTimer会自动保留所有NSInvocation的参数。
如果你没有把一个NSInvocation作为一个parameter passing给NSTimer,并且计划让它坚持一段时间,你必须调用它的-retainArguments
方法。 否则,在调用调用之前,其参数可能会被释放,最终导致代码崩溃。 以下是如何做到这一点:
NSMethodSignature *signature = ...; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; id arg1 = ...; id arg2 = ...; [invocation setTarget:...]; [invocation setSelector:...]; [invocation setArgument:&arg1 atIndex:2]; [invocation setArgument:&arg2 atIndex:3]; [invocation retainArguments]; // If you do not call this, arg1 and arg2 might be deallocated. [self someMethodThatInvokesYourInvocationEventually:invocation];
你可以尝试使用这个更好的库: http : //cocoawithlove.com/2008/03/construct-nsinvocation-for-any-message.html
我用NSInvocation构build了一个调用各种方法types的简单例子。
我有问题使用obj_msgSend调用多个参数