In this article I'm going to cover the basics and usages of NSInvocation.

What is NSInvocation?

Apple Developer Reference describes NSInvocation this way:

An NSInvocation is an Objective-C message rendered static, that is, it is an action turned into an object. NSInvocation objects are used to store and forward messages between objects and between applications, primarily by NSTimer objects and the distributed objects system.

When we call a method or access a member data of an object in our application, we are actually sending a message. Usually we don't send messages explicitly in our code since the compiler does the work for us. What NSInvocation brings to us is the ability to manually send a message to an object. So a NSInvocation object's job is to send messages; hence we create an object of NSInvocation class, we describe the aspects of the message and finally we send it to our target. The most useful advantage of NSInvocation is that it's an object so we can pass it as an argument to other methods.

Simple NSInvocation example

Suppose we have a dummy object named myDummyObject and it is an object of class myClass. in myClass we have a defined method named sayHelloWorld without any arguments. The simplest way to execute sayHelloWorld method is:

[myDummyObject sayHelloWorld];
1:

Select allOpen in new window

In fact this line causes the compiler to create a message which says "execute sayHelloWorld method" and sends it to the target object which is myDummyObject here.
Now we want to create the same message manually and send it to myDummyObject using NSInvocation.

A selector describes which method we want to call:

SEL selector = @selector(sayHelloWorld);
1:

Select allOpen in new window

Our NSInvocation object needs to know whether the target object has declared the method or if not throws an exception, so it should utilize some search algorithm to achieve this: A method signature is fingerprint of a method which depends on its return value, number of arguments it takes and their types. Therefore our NSInvocation will be able to search through the target object's methods list to see whether it has defined the method or not. This signature is created using methodSignatureForSelector method which every NSObject descendent has this method. In this case sayHelloWorld is a method of myClass. myDummyObject is an object of myClass so we should call methodSignatureForSelector on myDummyObject to return the signature for the method named sayHelloWorld using the selector we declared above:

NSMethodSignature *signature = [myDummyObject methodSignatureForSelector:selector];
1:

Select allOpen in new window

We create our NSInvocation object based on the method signature we declared:

        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
1:

Select allOpen in new window

NSInvocation objects also wants to have our selector:

        [invocation setSelector:selector];
1:

Select allOpen in new window

Here we specified our target object which we want our message to be sent to:

        [invocation setTarget:myDummyObject];
1:

Select allOpen in new window

The final step here. Commanding our NSInvocation object to send the message.

        [invocation invoke];
1:

Select allOpen in new window

NSInvocation to call a method with arguments

Suppose myDummyObject contains a method as follows:

-(void)myFunctionWithArg1: (NSString*) arg1 Arg2: (NSString *) arg2 Arg3: (NSString *) arg3 Arg4: (NSString *) arg4
{
NSLog(@"I am a function with 4 arguments: <%@> <%@> <%@> <%@>" , arg1, arg2, arg3, arg4);
}
1:
2:
3:
4:

Select allOpen in new window

The normal way of calling this method is:

[myDummyObject myFunctionWithArg1:@"First" Arg2:@"Second" Arg3:@"Third" Arg4:@"Fourth"];
1:

Select allOpen in new window

Now we want to create the message manually using NSInvocation. As I explained above:

SEL selector = @selector(myFunctionWithArg1:Arg2:Arg3:Arg4:);
NSMethodSignature *signature = [myDummyObject methodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setTarget:myDummyObject];
[invocation setSelector:selector];
1:
2:
3:
4:
5:

Select allOpen in new window

We define four strings. We will pass them through our NSInvocation toward the target object:

    NSString *arg1 = @"First";
NSString *arg2 = @"Second";
NSString *arg3 = @"Third";
NSString *arg4 = @"Fourth";
1:
2:
3:
4:

Select allOpen in new window

This is the way to set the arguments for the method. You can use SetArgument:atIndex for each argument at the specified index. 
Some notes about SetArgument:atIndex method:
1- The first argument should be the address of the variable you want to set. (You may encounter bridging if you are on ARC mode)
2- Indexes start at 2 so e.g. index 2 is the first argument of the method.

    [invocation setArgument:&arg1 atIndex:2];
[invocation setArgument:&arg2 atIndex:3];
[invocation setArgument:&arg3 atIndex:4];
[invocation setArgument:&arg4 atIndex:5];
1:
2:
3:
4:

Select allOpen in new window

And finally invoking our message:

    [invocation invoke];
1:

Select allOpen in new window

Using NSInvocation for call-backs

The most interesting usage of NSInvocation is that we can setup a call-back method for another method using NSInvocation. Now you may ask "what is a call-back method?" There are many asynchronous operations such as NSURLConnection (which is bound to transfer some data through a network) or NSXMLParser (which has the duty to parse a XML document). Most times these operations do not return their results immediately. We can request and setup many of such operations to call our desired methods (call-back method) when they are done (may also pass the result to our call-back method through arguments).

NSInvocation with call-back example

Suppose myDummyObject has a method named processMyTasksWithCallBackFunction as follows: processMyTasksWithCallBackFunction dispatches its tasks asynchronously using GCD.

-(void)processMyTasksWithCallBackFunction: (NSInvocation *) invocation
{
dispatch_async(dispatch_get_main_queue(), ^{ @autoreleasepool {
NSLog(@"Performing tasks like accessing a web service or preparing data for app");
sleep(3);//waiting 3 seconds
NSLog(@"DONE! Now calling the callback function..."); ///////// tasks are done; return the results through the NSInvocation object
///////// NSInvocation is supposed to point to a method which takes 4 NSString arguments NSString *arg1 = @"Result1";
NSString *arg2 = @"Result2";
NSString *arg3 = @"Result3";
NSString *arg4 = @"Result4";
[invocation setArgument:&arg1 atIndex:2];
[invocation setArgument:&arg2 atIndex:3];
[invocation setArgument:&arg3 atIndex:4];
[invocation setArgument:&arg4 atIndex:5];
[invocation invoke];
}
});
}
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:

Select allOpen in new window

Now we want to call processMyTasksWithCallBackFunction method and grab the results. Before that we have to declare a call-back method which takes 4 arguments (in our example). We declare this method in current class where we are calling processMyTasksWithCallBackFunction from. (Of course we can setup the call-back method from a remote object too.)

-(void)myFunctionWithArg1: (NSString*) arg1 Arg2: (NSString *) arg2 Arg3: (NSString *) arg3 Arg4: (NSString *) arg4
{
NSLog(@"I am a call-back method with 4 arguments: <%@> <%@> <%@> <%@>" , arg1, arg2, arg3, arg4);
}
1:
2:
3:
4:

Select allOpen in new window

Now we have to create the NSInvocation for our call-back method to be passed to processMyTasksWithCallBackFunction. Notice we don't set the arguments here because processMyTasksWithCallBackFunction will set them when it's done.

    SEL CB_selector = @selector(myFunctionWithArg1:Arg2:Arg3:Arg4:);
NSMethodSignature *CB_signature = [self methodSignatureForSelector:CB_selector];
NSInvocation *CB_invocation = [NSInvocation invocationWithMethodSignature:CB_signature];
[CB_invocation setTarget:self];//Since we declared the call-back method in current class
[CB_invocation setSelector:CB_selector];
1:
2:
3:
4:
5:

Now we can call the asynchronous method:

[processMyTasksWithCallBackFunction: CB_invocation];
1:
Sample Output:
2011-09-13 12:35:35.601 InvocationTest[6710:4903] Performing tasks like accessing a web service or preparing data for app
2011-09-13 12:35:38.603 InvocationTest[6710:4903] DONE! Now calling the callback function...
2011-09-13 12:35:38.604 InvocationTest[6710:4903] I am a call-back method with 4 arguments: <Result1> <Result2> <Result3> <Result4>

Conclusion

NSInvocation can bring great flexibility to your applications/frameworks in many situations. I hope this clarified NSInvocation and its usages. Please let me know if you have any question.

NSInvocation Basics的更多相关文章

  1. Objective-C中NSInvocation的使用

    OC中调用方法某个对象的消息呦两种方式: #1. performanceSelector: withObject: #2. NSInvocation. 第一个PerformaceSelector比较常 ...

  2. Assembler : The Basics In Reversing

    Assembler : The Basics In Reversing Indeed: the basics!! This is all far from complete but covers ab ...

  3. iOS开发——网络篇——UIWebview基本使用,NSInvocation(封装类),NSMethodSignature(签名),JavaScript,抛异常,消除警告

    一.UIWebView简介 1.UIWebView什么是UIWebViewUIWebView是iOS内置的浏览器控件系统自带的Safari浏览器就是通过UIWebView实现的 UIWebView不但 ...

  4. The Basics of 3D Printing in 2015 - from someone with 16 WHOLE HOURS' experience

    全文转载自 Scott Hanselman的博文. I bought a 3D printer on Friday, specifically a Printrbot Simple Metal fro ...

  5. Cadence UVM基础视频介绍(UVM SV Basics)

    Cadence关于UVM的简单介绍,包括UVM的各个方面.有中文和英文两种版本. UVM SV Basics 1 – Introduction UVM SV Basics 2 – DUT Exampl ...

  6. C basics

    C 日记目录 C basics ................ writing Numeration storage   , structor space assigning pointer,  a ...

  7. Xperf Basics: Recording a Trace(转)

    http://randomascii.wordpress.com/2011/08/18/xperf-basics-recording-a-trace/   This post is obsolete ...

  8. Xperf Analysis Basics(转)

      FQ不易,转载 http://randomascii.wordpress.com/2011/08/23/xperf-analysis-basics/ I started writing a des ...

  9. Radio Basics for RFID

    Radio Basics for RFID The following is excerpted from Chapter 3: Radio Basics for UHF RFID from the ...

随机推荐

  1. WEBUS2.0 In Action - 索引操作指南(2)

    上一篇:WEBUS2.0 In Action - 索引操作指南(1) | 下一篇:WEBUS2.0 In Action - 搜索操作指南(1) 3. 添加.删除.撤销删除和修改文档 在WEBUS中要将 ...

  2. Android 系统属性

    /************************************************************************ * Android 系统属性 * 说明: * 由于需 ...

  3. 最大熵模型 Maximum Entropy Model

    熵的概念在统计学习与机器学习中真是很重要,熵的介绍在这里:信息熵 Information Theory .今天的主题是最大熵模型(Maximum Entropy Model,以下简称MaxEnt),M ...

  4. 【英语】Bingo口语笔记(72) - play系列

  5. dynamic_cast

    作为四个内部类型转换操作符之一的dynamic_cast和传统的C风格的强制类型转换有着巨大的差别.除了dynamic_cast以外的转换,其行为的都是在编译期就得以确定的,转换是否成功,并不依赖被转 ...

  6. Arduino运行时突然[卡死在某一行/立即重启/串口输出乱码/程序执行不正常]的可能原因

    1.这一行是分配内存,而内存不够了(Arduino uno只有2k) 2.内存本身已经只剩一点点了,于是就有莫名其妙的问题 3.没有调用Wire.begin().xx.setup()之类的操作!

  7. php curl简单使用

    使用PHP的cURL库可以简单和有效地去抓网页,您只需要运行一个脚本,然后分析一下您所抓取的网页,然后就可以以程序的方式得到您想要的数据了.无论是您想从一个链接上取部分数据,或是取一个XML文件并把其 ...

  8. sessionFactory.getCurrentSession()的引出

    当业务逻辑中需要开启事务执行,业务逻辑也要调用底层操作数据库的函数,那函数也要开启事务操作. 如果用sessionFactory.openSession()的话会引起处理不在同一个事务中,会造成出错. ...

  9. 把两个DataTable连接起来,相当于Sql的Inner Join方法

    在C#中把两个DataTable连接起来,相当于Sql的Inner Join方法 作者:浪漫十一狼在下面的例子中实现了3个Join方法,其目的是把两个DataTable连接起来,相当于Sql的Inne ...

  10. iOS学习笔记之回调(二)

    写在前面 上一篇学习笔记中简单介绍了通过目标-动作对实现回调操作:创建两个对象timer和logger,将logger设置为timer的目标,timer定时调用logger的sayOuch函数.在这个 ...