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