這是幾個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
這邊我提供了兩個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
還在忙報告,未學到
回覆刪除遲點再看- -"