NSInvocation 傻瓜式的吗?
NSInitation
到底是如何工作的? 有好的介绍吗?
我在理解以下代码(来自Mac OS X 的 Cocoa 编程,第 3 版)的工作原理时遇到了一些问题,但也能够独立于教程示例应用这些概念。 代码:
- (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 的委托概念,但非类型化?
书中并没有 100% 清楚地说明这一点,因此我正在寻找真正的 Cocoa/Obj-C 专家提供的补充内容,同样的目标是让我理解简单(-ish)示例下的基本概念。 我真的希望能够独立应用这些知识——直到第 9 章,我做到这一点没有任何困难。 但现在 ...
How exactly does NSInvocation
work? Is there a good introduction?
I’m specifically having issues understanding how the following code (from Cocoa Programming for Mac OS X, 3rd Edition) works, but then also be able to apply the concepts independently of the tutorial sample. The code:
- (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];
}
I get what it’s trying to do. (BTW, employees
is an NSArray
of a custom Person
class.)
Being a .NET guy, I try to associate unfamiliar Obj-C and Cocoa concepts to roughly analogous .NET concepts. Is this similar to .NET’s delegate concept, but untyped?
This isn’t 100% clear from the book, so I’m looking for something supplemental from real Cocoa/Obj-C experts, again with the goal that I understand the fundamental concept beneath the simple(-ish) example. I'm really looking to be able to independently apply the knowledge -- up until chapter 9, I was having no difficulty doing that. But now ...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
根据 Apple 的 NSInitation 类参考:
而且,更详细一点:
消息的概念是 Objective-C 哲学的核心。 任何时候你调用一个方法,或者访问某个对象的变量,你都在向它发送一条消息。 当您想要在不同的时间点向对象发送消息或多次发送相同的消息时,
NSInitation
会派上用场。NSInspiration
允许您描述要发送的消息,然后调用它(实际上将其发送到目标对象)。例如,假设您想将字符串添加到数组中。 您通常会按如下方式发送
addObject:
消息:现在,假设您想使用
NSInvocau
在其他某个时间点发送此消息:首先,您需要准备与
NSMutableArray
的addObject:
选择器一起使用的NSInspiration
对象:接下来,您将指定将消息发送到哪个对象:
指定消息您希望发送到该对象:
并填写该方法的任何参数:
请注意,对象参数必须通过指针传递。 感谢 Ryan McCuaig 指出这一点,请参阅 Apple 文档了解更多详细信息。
此时,
myInitation
就是一个完整的对象,描述了一条可以发送的消息。 要实际发送消息,您可以调用:最后一步将导致消息被发送,实质上是执行
[myArray addObject:myString];
。把它想象成发送电子邮件。 您打开一封新电子邮件(
NSInitation
对象),填写您想要将其发送给的人(对象)的地址,输入收件人的消息(指定一个选择器
和参数),然后单击“发送”(调用invoke
)。有关详细信息,请参阅使用 NSInitation。
请参阅如果上述方法不起作用,请使用 NSInitation 。
NSUndoManager
使用NSInitation
对象,以便它可以反转命令。 本质上,您正在做的就是创建一个 NSInitation 对象来表示:“嘿,如果您想撤消我刚刚所做的事情,请使用这些参数将此消息发送到该对象”。 您将 NSInspiration 对象提供给 NSUndoManager,它会将该对象添加到可撤消操作的数组中。 如果用户调用“Undo”,NSUndoManager
只需在数组中查找最近的操作,并调用存储的NSInvocau
对象来执行必要的操作。有关更多详细信息,请参阅注册撤消操作。
According to Apple's NSInvocation class reference:
And, in a little more detail:
The concept of messages is central to the objective-c philosophy. Any time you call a method, or access a variable of some object, you are sending it a message.
NSInvocation
comes in handy when you want to send a message to an object at a different point in time, or send the same message several times.NSInvocation
allows you to describe the message you are going to send, and then invoke it (actually send it to the target object) later on.For example, let's say you want to add a string to an array. You would normally send the
addObject:
message as follows:Now, let's say you want to use
NSInvocation
to send this message at some other point in time:First, you would prepare an
NSInvocation
object for use withNSMutableArray
'saddObject:
selector:Next, you would specify which object to send the message to:
Specify the message you wish to send to that object:
And fill in any arguments for that method:
Note that object arguments must be passed by pointer. Thank you to Ryan McCuaig for pointing that out, and please see Apple's documentation for more details.
At this point,
myInvocation
is a complete object, describing a message that can be sent. To actually send the message, you would call:This final step will cause the message to be sent, essentially executing
[myArray addObject:myString];
.Think of it like sending an email. You open up a new email (
NSInvocation
object), fill in the address of the person (object) who you want to send it to, type in a message for the recipient (specify aselector
and arguments), and then click "send" (callinvoke
).See Using NSInvocation for more information.
See Using NSInvocation if the above is not working.
NSUndoManager
usesNSInvocation
objects so that it can reverse commands. Essentially, what you are doing is creating anNSInvocation
object to say: "Hey, if you want to undo what I just did, send this message to that object, with these arguments". You give theNSInvocation
object to theNSUndoManager
, and it adds that object to an array of undoable actions. If the user calls "Undo",NSUndoManager
simply looks up the most recent action in the array, and invokes the storedNSInvocation
object to perform the necessary action.See Registering Undo Operations for more details.
下面是 NSIncation 的一个简单示例:
当调用时 -
[self hello:@"Hello" world:@"world"];
- 该方法将:最后,你会得到如下的打印输出:
当然,目标对象 self 必须继续存在,NSTimer 才能向其发送 NSInitation。 例如,Singleton 对象,或者在应用程序运行期间存在的 AppDelegate。
更新:
如上所述,当您将 NSInitation 作为参数传递给 NSTimer 时,NSTimer 会自动保留 NSInitation 的所有参数。
如果您不将 NSIncation 作为参数传递给 NSTimer,并计划让它保留一段时间,则必须调用其
-retainArguments
方法。 否则,它的参数可能会在调用之前被释放,最终导致代码崩溃。 操作方法如下:Here's a simple example of NSInvocation in action:
When called -
[self hello:@"Hello" world:@"world"];
- the method will:In the end, you'll get a printout like so:
Of course, the target object
self
must continue to exist for the NSTimer to send the NSInvocation to it. For example, a Singleton object, or an AppDelegate which exists for the duration of the application.UPDATE:
As noted above, when you pass an NSInvocation as an argument to an NSTimer, the NSTimer automatically retains all of the NSInvocation's arguments.
If you are not passing an NSInvocation as an argument to an NSTimer, and plan on having it stick around for a while, you must call its
-retainArguments
method. Otherwise its arguments may be deallocated before the invocation is invoked, eventually causing your code to crash. Here's how to do it:您可以尝试使用这里的库,它更好: http: //cocoawithlove.com/2008/03/construct-nsinspiration-for-any-message.html
You could try just using the library here which is much nicer: http://cocoawithlove.com/2008/03/construct-nsinvocation-for-any-message.html
我构建了一个使用 NSInitation 调用各种方法类型的简单示例。
我在使用 obj_msgSend 调用多个参数时遇到问题
https://github.com/clearbrian/NSInitation_Runtime
I build a simple example of calling various method types with NSInvocation.
I had problems calling multiple params using obj_msgSend
https://github.com/clearbrian/NSInvocation_Runtime