为傻瓜辩护?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (26)

我特别有问题,理解以下代码(从Mac OS X的可可编程,第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];
}

作为一个.NET的人,我尝试将不熟悉的Obj-C和Cocoa概念与大致类似的.NET概念联系起来。这与.NET的委托概念相似,但没有类型吗?

这本书没有100%清楚地说明这一点,所以我正在寻找来自真正的可可/Obj-C专家的补充,同样,我的目标是理解简单(-ish)示例下面的基本概念。

提问于
用户回答回答于

根据苹果的NSIn传类参考:

NSInvocation是一个对象-C消息呈现静态,也就是说,它是一个动作变成一个对象。

然后,在一个更详细:

信息的概念是目标c哲学的核心.。任何时候,当调用一个方法,或者访问某个对象的变量时,都会向它发送一条消息。NSInvocation当想要在不同的时间点向对象发送消息或多次发送相同的消息时,就会派上用场。NSInvocation允许你描述你要发送的信息,然后调用稍后它(实际上将其发送到目标对象)。

例如,假设要向数组中添加字符串。你通常会把addObject:电文如下:

[myArray addObject:myString];

现在,假设你想用NSInvocation若要在其他时间点发送此消息,请执行以下操作:

首先,你要准备一个NSInvocation对象用于NSMutableArrayaddObject:选择器:

NSMethodSignature * mySignature = [NSMutableArray
    instanceMethodSignatureForSelector:@selector(addObject:)];
NSInvocation * myInvocation = [NSInvocation
    invocationWithMethodSignature:mySignature];

接下来,将指定要将消息发送到哪个对象:

[myInvocation setTarget:myArray];

Specify the message you wish to send to that object:

[myInvocation setSelector:@selector(addObject:)];

并填写该方法的任何论据:

[myInvocation setArgument:&myString atIndex:2];

注意,对象参数必须通过指针传递。

在这一点上,myInvocation是一个完整的对象,描述可以发送的消息。要真正发送消息,可以调用:

[myInvocation invoke];

最后一步将导致发送消息,实质上是执行[myArray addObject:myString];...

把它想象成发一封电子邮件。你打开一封新邮件(NSInvocation对象),填写要将其发送给的人(对象)的地址,键入收件人的邮件(指定selector和参数),然后单击“发送”(调用invoke)

NSUndoManager使用NSInvocation对象,以便它能够倒向命令。本质上,所做的是创建一个NSInvocation反对这样说:“嘿,如果你想撤销我刚才做的事情,用这些参数把这个消息发送给那个对象”。你给NSInvocation对象的NSUndoManager,它将该对象添加到一系列不可撤销的操作中。如果用户调用“撤销”,NSUndoManager只需查找数组中最近的操作,并调用存储的NSInvocation对象来执行必要的操作。

用户回答回答于

下面是NSInvoation在实际操作中的一个简单示例:

- (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"];-该方法将:

  • 打印“你好世界!”
  • 为自己创建一个NSMethod签名。
  • 创建并填充一个NSInquest,并调用它自己。
  • 将NSInvoation传递给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向其发送NSInvoation。

最新情况:

如前所述,将NSInvoation作为参数传递给NSTimer时,NSTimer自动保留所有NSInvoation的参数。

如果没有将NSInvoation作为一个参数传递给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];

扫码关注云+社区