在寫程式的時候, 常常會有需要呼叫好幾個method, 然後在時間上有所需別; 最常遇到的都是希望Layout改變完成之後再去執行下一步動作, 如果是一堆layout animation, 就會很常使用到delay去做一些時間差的區別.
can do it this way
1
2
3
4
5
6
7
|
- (void)currentMehtod { SEL action2 = @selector(action2:); [object performSelector:action2 withObject:data afterDelay:1.f]; /** … * do somethig after … **/ } |
一開始使用的時候覺得還好, 但是慢慢的發現如果我的method一開始寫的時候帶入多個參數, 如果用上面的方式, 就要改寫本來的method, 這樣又得花時間, 而且可能最後都是帶入NSDictionary
的物件, 在把需要的資料拉出來, 常常會把map的key打錯又多花很多時間在debug.
在StackOverflow上查了參數數量的問題, 沒想到還真的有一個很棒的解法, 就是 NSInvocation
.
NSInvocation
NSInvocation的使用有一個地方要特別注意, invocation不能使用 alloc
跟init
來建立實體, 只能使用invocationWithMethodSignature:
來建立object.
object的method
1
2
3
|
- (void)actionInvokeArgument1:(NSInteger)arg1 arg2:(NSNumber *)arg2 { NSLog(@"action: arg1 + arg2=%d", arg1 + [arg2 integerValue]); } |
使用Invocation, mehtod所帶入的參數也不用都轉成object, int、BOOL…etc.都可以使用
建立一個NSInvocation實體
1
2
3
|
SEL mySelector = @selector(actionInvokeArgument1:arg2:); NSMethodSignature* signature1 = [self methodSignatureForSelector:mySelector]; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature1]; |
我們先使用NSObject
的instance mehtod(也可以使用Class mehtod, 依照個人使用習慣), 先取得一個NSMethodSignature
物件, 並建立一個NSInvocation.
NSMethodSignature的numberOfArguments最小值是2; 0跟1是給預設的隱藏參數使用(self & _cmd). 從2開始才是method-spec使用.
這時取得的invocation只有簡單的method可帶入的argument數量, 在正式調用之前你還需要設定target
跟selector
.
設定invocation並調用
1
2
3
4
5
6
7
|
[invocation setTarget:self]; [invocation setSelector:mySelector]; NSInteger arg1 = 1; NSNumber* arg2 = @2; [invocation setArgument:&arg1 atIndex:2]; [invocation setArgument:&arg2 atIndex:3]; [invocation invoke]; |
使用NSInvocation設定參數時, index要從2開始.
取得回傳值
1
2
3
|
NSInteger retVal; [invocation getReturnValue:&retVal]; NSLog(@"%d", retVal); |
如果要延遲的話可以這樣使用
delay invoke
1
|
[invocation performSelector:@selector(invoke) withObject:nil afterDelay:1];
|
要注意的是, 如果會需要取得回傳值, 可能不適合使用delay的方式~
转载:http://greenchiu.github.io/blog/2013/04/27/yong-nsinvocationlai-qu-dai-performselector/
在ios直接调用某个对象的消息是方法有两种:
一:performselector:withObject:
二:invocation
第一种方式比较简单,能完成简单的调用。但是对于>2个的参数或者有返回值的处理,那就需要做些额外工作才能搞定。那么在这种情况下,我们就可以使用NSInvocation来进行这些相对复杂的操作
NSInvocation可以处理参数、返回值。会java的人都知道凡是操作,其实NSInvocation就相当于反射操作。
-
- NSMethodSignature *sig= [[AsynInvoke class] instanceMethodSignatureForSelector:@selector(invokeMethod:)];
-
- NSInvocation *invocation=[NSInvocation invocationWithMethodSignature:sig];
-
- [invocation setTarget:self];
-
- [invocation setSelector:@selector(invokeMethod:)];
-
- NSInteger num=10;
- [invocation setArgument:&num atIndex:2];
-
- [invocation retainArguments];
-
- [invocation invoke];
-
-
-
-
-
- const char *returnType = sig.methodReturnType;
-
- id returnValue;
-
- if( !strcmp(returnType, @encode(void)) ){
- returnValue = nil;
- }
-
- else if( !strcmp(returnType, @encode(id)) ){
- [invocation getReturnValue:&returnValue];
- }
- else{
-
-
-
- NSUInteger length = [sig methodReturnLength];
-
- void *buffer = (void *)malloc(length);
-
- [invocation getReturnValue:buffer];
-
-
- if( !strcmp(returnType, @encode(BOOL)) ) {
- returnValue = [NSNumber numberWithBool:*((BOOL*)buffer)];
- }
- else if( !strcmp(returnType, @encode(NSInteger)) ){
- returnValue = [NSNumber numberWithInteger:*((NSInteger*)buffer)];
- }
- returnValue = [NSValue valueWithBytes:buffer objCType:returnType];
- }
调用步骤:
- - (NSString *) myMethod:(NSString *)param1 withParam2:(NSNumber *)param2{
-
- NSString *result = @"Objective-C";
- NSLog(@"Param 1 = %@", param1);
- NSLog(@"Param 2 = %@", param2);
- return(result);
- }
-
- - (void) invokeMyMethodDynamically {
- SEL selector = @selector(myMethod:withParam2:);
-
- NSMethodSignature *methodSignature = [[self class] instanceMethodSignatureForSelector:selector];
-
- NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
-
- [invocation setTarget:self];
-
- [invocation setSelector:selector];
-
- NSString *returnValue = nil;
- NSString *argument1 = @"First Parameter";
- NSNumber *argument2 = [NSNumber numberWithInt:102];
-
- [invocation setArgument:&argument1 atIndex:2];
- [invocation setArgument:&argument2 atIndex:3];
- [invocation retainArguments];
- [invocation invoke];
- [invocation getReturnValue:&returnValue];
-
- NSLog(@"Return Value = %@", returnValue);
- }
-
-
To do this, you need to follow these steps:
1. Form a SEL value using the name of the method and its parameter names (as
explained in Recipe 1.7).
2. Form a method signature of type NSMethodSignature out of your SEL value.
3. Form an invocation of type NSInvocation out of your method signature.
4. Tell the invocation what object you are targeting.
5. Tell the invocation what selector in that object you want to invoke.
6. Assign any arguments, one by one, to the invocation.
7. Invoke the method using the invocation object and demand a return value (if any).