2009-11-11 61 views
0

我想(在運行時)的參數綁定到一個功能,你可以在boost ::綁定做 - 有點像下面這樣:目標C運行時參數綁定

-(void)myFuncWithParameter:(NSString*)param { 
    NSLog(param); 
} 

-(void)init { 

    UIButton *helloButton = [UIButton buttonWithType:UIButtonTypeCustom]; 
    [helloButton addTarget:self action:@selector(myFuncWithParameter:@"hello") forControlEvents:UIControlEventTouchUpInside]; 

} 

所以。 ..我動態綁定(在運行時)的價值@「你好」的參數。

顯然上面的不正確的語法。有誰知道這是否可能和正確的語法?

乾杯, Nick。

+0

事後考慮 - 我可以添加一個KVP到按鈕層 [helloButton.layer setValue:@「hello」forKey:@「param1」]; ...然後參考按鈕,因爲它傳遞給被調用的函數......但這是一個非常醜陋的解決方案! – 2009-11-11 11:48:51

回答

1

一般的答案是目標動作機制只允許一個目標,一個發送者和一個接收發送者的消息;因此,如果您需要訪問數據,則必須從目標或發件人處獲取數據。

一種選擇是創建一個代表參數值,方法和對象的綁定的類。這個類將有一個動作調用對象的方法,傳遞值。使用這個類的一個實例作爲目標。這裏有一個簡單的例子:

@interface UnaryBinder : NSObject { 
    id target; 
    SEL selector; 
    id parameter; 
} 
@property id target; 
@property SEL selector; 
@property (retain) id parameter; 
-(id)initWithTarget:(id)anObject selector:(SEL)aSelector param:(id)aParameter; 
-(void)action:(id)sender; 
@end 

@implementation UnaryBinder 
... 
-(void)action:(id)sender { 
    [target performSelector:selector withObject:parameter]; 
} 
@end 

如果你想支持的任意數目參數的,你需要使用NSInvocation的(如路易提到),而不是performSelector:withObject。當然,控件不保留它們的目標,所以你需要一些方法來保持UnaryBinder。此時,您可以跳過特殊課程並將數據存儲在控件中,如您在評論中提到的有關使用KVP的內容。或者,將操作分解到控制器類中,並使用該實例作爲目標。 UnaryBinder及其流行在涉及目標行動時並沒有提供任何優勢。對於相關的主題,谷歌「更高級的消息傳遞」。

+0

兩個可能同樣好的答案,但我在這裏給它,因爲它的理解和實施稍微簡單! N – 2009-11-23 09:33:51

+0

「當然,控件不會保留它們的目標,所以您需要一些方法來保留UnaryBinder。」這是這個解決方案的問題 – user102008 2011-04-23 01:32:25

+0

@ user102008:這只是一個「問題」,因爲在我的答案中沒有明確提到存儲「UnaryBinder」,這就是我提到它的原因。此外,沒有明確解決方案的唯一原因是沒有一個通用的解決方案,尼克沒有給出關於他具體設計的許多細節; UnaryBinder如何存儲取決於設計需求。一個'UnaryBinder'可以很容易地存儲在一個控制器中(例如),但是這個問題中並沒有提到可用的特定控制器。 – outis 2011-04-23 02:16:44

3

簡短答案是否定的,或者至少不是在那個級別。

長的答案是,在技術上可以構建類似於使用NSInvocations(和/或forwardInvocation:)的東西,在methodForSelector中做一些聰明的事情,或者通過動態註冊方法實現,但這非常棘手,特別是如果你關心速度。

如果我有一些代碼來建立這樣的curry方法真的很值得,我會做的就是這樣(寫在這個評論中,未經測試);

//FIXME: In a real implementation you would do some mangling, this code will get confused if you have _s in the curried selector, and thus could be exploitable 

//This method makes a unique selector by mangling the arguments 
- (SEL) selectorForSelector:(SEL)bindSel withString:(NSString *)bindString { 
    NSString *mangle = [NSString *stringWithFormat:@"LGBind_%@_%@"], NSStringFromSelector(bindSel), bindString]; 
    SEL retval = NSSelectorFromString(mangle); 

    //Register the imp. You probably want to check if it is already reg 
    if (![self respondsToSelector:retval]) { 
    class_addMethod([self class], retval, LGBind_IMP, "[email protected]:")l 
    } 
} 

//Generic dispatcher imp 
void LGBind_IMP(id self, SEL _cmd) { 
    NSString *selectorName = NSStringFromSelector(_cmd); 
    NSArray *array [selectorName componentsSeparatedByString:@"_"]; 

    //Skip index 0; it is @"LGBind" 
    NSString *originalSelectorString = [array objectAtIndex:1]; 
    NSString *originalArgString = [array objectAtIndex:2]; 

    //Get our the SEL and the IMP 
    SEL originalSEL = NSSelectorFromString(originalSelectorString); 
    IMP originalIMP = [self methodForSelector:originalSEL]; 

    //call the original imp 
    originalIMP([self class], originalSEL, originalArgString); 
} 

顯然,這取決於你可以做不同的事情的地方您的具體需求,比如你可以懶洋洋地在forwardInvocation的小鬼,或約在實例字典的managled選擇藏匿的數據,而不是僅僅managling成選擇器名稱。