代码之家  ›  专栏  ›  技术社区  ›  John Rudy

N假人的位置?

  •  136
  • John Rudy  · 技术社区  · 16 年前

    到底是怎么回事 NSInvocation 工作?有什么好的介绍吗?

    i_m在理解以下代码(从 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 是一个 NSArray 风俗习惯 Person 班级)

    作为一个.NET用户,我试图将不熟悉的obj-c和cocoa概念与大致相似的.NET概念联系起来。这是否与.NET_的委托概念类似,但不是类型化的?

    这一点在书中并不十分清楚,所以我在寻找真正的可可/obj-c专家的补充,我的目标是理解简单的(ish)例子下面的基本概念。我真的希望能够独立地应用这些知识——直到第9章,我做这些都没有困难。但是现在…

    事先谢谢!

    4 回复  |  直到 8 年前
        1
  •  277
  •   unom    8 年前

    根据 Apple's NSInvocation class reference :

    NSInvocation 是一个Objective-C消息呈现为静态的,也就是说,它是一个动作转化为一个对象。

    而且,在 小的 更多细节:

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


    例如,假设您想向数组中添加一个字符串。您通常会发送 addObject: 信息如下:

    [myArray addObject:myString];
    

    现在,假设你想使用 NS调用 要在其他时间点发送此消息:

    首先,你要准备一个 NS调用 用于的对象 NSMutableArray AdObjult: 选择器:

    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's documentation 了解更多详细信息。

    在这一点上, myInvocation 是一个完整的对象,描述可以发送的消息。要实际发送消息,您可以致电:

    [myInvocation invoke];
    

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

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

    Using NSInvocation 更多信息。 见 Using NSInvocation 如果上述情况不起作用。


    NSUndoManager 使用 NS调用 对象,以便它可以 颠倒 命令。本质上,你所做的就是创造一个 NS调用 对象说:“嘿,如果你想撤销我刚才所做的,用这些参数把这个消息发送给那个对象。”你给 NS调用 对象到 恩桑多梅纳 ,并将该对象添加到可撤消操作的数组中。如果用户调用“撤消”, 恩桑多梅纳 只需查找数组中最近的操作,并调用存储的 NS调用 对象以执行必要的操作。

    Registering Undo Operations 了解更多详细信息。

        2
  •  46
  •   Dave    13 年前

    下面是一个简单的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"]; -该方法将:

    • 打印“你好,世界!”
    • 为自己创建nsmethodSignature。
    • 创建并填充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发送给它。例如,A 独生子女 对象,或应用程序持续时间内存在的AppDelegate。


    更新:

    如上所述,当您将nsInvocation作为参数传递给nsTimer时,nsTimer会自动保留nsInvocation的所有参数。

    如果你不把一个nsinvocation作为一个论点传递给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];
    
        3
  •  5
  •   Casebash    15 年前

    你可以试着用这里的图书馆,这是更好的: http://cocoawithlove.com/2008/03/construct-nsinvocation-for-any-message.html

        4
  •  0
  •   brian.clear    11 年前

    我构建了一个使用nsInvocation调用各种方法类型的简单示例。

    我在使用obj-msgsend调用多个参数时遇到问题

    https://github.com/clearbrian/NSInvocation_Runtime

    推荐文章