如何把Target/Action放进array里面
Target-Action相信这个design pattern对于写ios一阵子的人都不陌生
这是几个ios fundamental design pattern之一
然而有时候我们会希望把几个target action放进array或是dictionary之中,或是直接当作member variable
但是SEL并不是一般继承于NSObject的class,所以不能直接放进Array当中
当然我们可以用
NSStringFromSelector(SEL aSelector)
以及
NSSelectorFromString(NSString *aSelectorName)
让SEL可以跟NSString*互换
但是怎么都觉得不是很方便
我就在想有没有比较漂亮的方法
我找了一下iOS foundation library,当中就属NSInvocation最合适
这个Class就是把target, action, arguments包在一起,
当我们唿叫-[NSInvocation invoke]
就会唿叫这个target的selector,并且传进这些arguments...
太棒了,这就是我要的class!!
但是NSInvocation的产生方式实在不怎么好用,如果我们要把这些东西全部丢进去
那我们需要如下面这段code
NSMethodSignature* sig =
[[target class] instanceMethodSignatureForSelector:@selector(mySelector:];
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:sig];
[invocation setTarget:target];
[invocation setSelector:selector];
看起来很不友善吧...
不好用的话,那我们就来自己动手做Category吧...
NSInvocation+PopcornyLu.h / NSInvocation+PopcornyLu.m
#import <Foundation/Foundation.h>
@interface NSInvocation (PopcornyLu)
+ (NSInvocation*) invocationWithTarget:(id)target
selector:(SEL)selector;
+ (NSInvocation*) invocationWithTarget:(id)target
selector:(SEL)selector
arguments:(id)firstArg, ... NS_REQUIRES_NIL_TERMINATION;
@end#import "NSInvocation+PopcornyLu.h"
@implementation NSInvocation (PopcornyLu)
+ (NSInvocation*) invocationWithTarget:(id)target
selector:(SEL)selector
{
NSMethodSignature* sig = [[target class] instanceMethodSignatureForSelector:selector];
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:sig];
[invocation setTarget:target];
[invocation setSelector:selector];
return invocation;
}
+ (NSInvocation*) invocationWithTarget:(id)target
selector:(SEL)selector
arguments:(id)firstArg, ...
{
NSMethodSignature* sig = [[target class] instanceMethodSignatureForSelector:selector];
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:sig];
[invocation setTarget:target];
[invocation setSelector:selector];
va_list args;
id arg;
va_start(args, firstArg);
NSUInteger index = 2;
for(arg = firstArg;
arg != nil;
arg = va_arg(args, id))
{
[invocation setArgument:&arg atIndex:index++];
}
va_end(args);
return invocation;
}
@end
这边我提供了两个Class messages来产生NSInvocation
其中第二个可以提供不定量的arguments.
使用上很简单
// Put invocations in array
NSArray* myActions =
[NSArray arrayWithObjects:
[NSInvocation invocationWithTarget:self
selector:@selector(action1)],
[NSInvocation invocationWithTarget:self
selector:@selector(action2:)
arguments:@"foo", nil],
[NSInvocation invocationWithTarget:self
selector:@selector(action3WithFoo:andBar:)
arguments:@"foo", @"bar", nil],
nil];
// invoke all the actions
for(NSInvocation* invocation in myActions)
{
[invocation invoke];
}
[补充]
当然也可以用block来取代target/action
以上面的例子我们可以用block来实作
NSArray* myActions2 =
[NSArray arrayWithObjects:
[[^(void){
[self action1];
} copy] autorelease],
[[^(void){
[self action2:@"foo"];
} copy] autorelease],
[[^(void){
[self action3WithFoo:@"foo" andBar:@"bar"];
} copy] autorelease],
nil];
// invoke all the actions
for(void(^invocation)() in myActions2)
{
invocation();
}
但是缺点是code比较凌乱一点,然后action1, action2:, action3WithFoo:withBar这些message都要在前面要先定义
稍微麻烦了点
但基本上Target/Action或是Block都有其方便之处
像这边我希望array creation的地方不要写太多code,所以我会选择用target/action
但有时候使用上会用inline block比较方便,那我就用block
- 评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
-
