[英]Objective-C - Storing block with parameters for callback
我有一個通用例程,它帶有一些參數。 就像是:
-(id) doStuff:(int)A:(int)B:(int)C {
//doStuff
return object;
}
我有一個UITableViewController
,其中包含許多自定義單元格,每個單元格都有自己的ID。 當單擊“保存”時,將迭代這些單元格,並且某些單元格在保存時需要“其他行為”。
到目前為止,我已經創建了一個“回調”對象,該對象在自定義單元格中存儲了一個NSString *
和一個委托。 在“保存”后,該單元格看起來是否有任何回調要應用和使用
SEL sel = NSSelectorFromString(Sel);
if([Del respondsToSelector:sel])
[Del performSelector:sel withObject:Cell];
現在效果不錯...但是,它需要我傳遞的方法對傳遞的Cell的ID進行切換/處理,我想避免這種情況。
這就是為什么我想使用塊代替的原因,但是我真的不知道如何在變量中存儲參數化塊。
我正在嘗試做的是:
聲明功能塊doStuff
。
id (^doStuff) (int, int, int) = ^(int A, int B, int C) {
//does Stuff
};
並將先前創建的塊添加為回調
[Cell addCallback:(^doStuff)(1, 2, 3)];
那一刻不能調用該塊,而應將其存儲在單元中,並且僅在適當的時候調用它。 我將如何正確處理?
非常感謝你。
編輯:我也想避免的是將塊的參數存儲在單元格中,並在調用時傳遞它們,因為這將需要我不必要地進一步專門化單元格。
聽起來您想要的是一個可以調用您的塊的塊,如下所示:
[cell addCallback:^{ doStuff(1, 2, 3); }];
但這是一個相當奇怪且令人費解的設計。 似乎只有一種方法可以編寫它,但是如果不更好地了解自己在做什么,很難給出具體的解決方案。
最直接的方法是創建一個typedef,其中包含塊參數的外觀,然后使用它來聲明新的屬性/ ivar。 以下示例代碼是從Sensible TableView框架SCCellActions類復制的:
typedef void(^SCCellAction_Block)(SCTableViewCell *cell, NSIndexPath *indexPath);
@interface SCCellActions : NSObject
...
@property (nonatomic, copy) SCCellAction_Block willDisplay;
...
@end
然后可以按如下所示設置屬性:
cellActions.willDisplay = ^(SCTableViewCell *cell, NSIndexPath *indexPath)
{
cell.backgroundColor = [UIColor yellowColor];
};
同樣,您可以聲明一個參數,如下所示:
...
- (void)callActionBlock:(SCCellAction_Block actionBlock)
{
if(actionBlock)
{
actionBlock(self.cell, self.cellIndexPath);
}
}
...
在這種情況下,應按以下方式調用該方法:
[myObject callActionBlock:^(SCTableViewCell *cell, NSIndexPath *indexPath {cell.backgroundColor = [UIColor yellowColor];}];
該答案基於Chuck的建議,並描述了我在實現它時遇到的陷阱。
創建:
Cell = [self CreateCell];
[Cell addCallback:^{ return doStuff(Cell, 1, 2, 3, 4) } At:ON_SAVE];
doStuff是一個局部塊,在單元格之前聲明。 我無法將其直接添加到單元格中,因為我還需要對塊中調用單元格的引用。
此時的陷阱:類變量。 一個塊將只保留...或更確切地說是“復制”局部變量,而不保留類變量。 假設“ Cell”是一個類變量,並由“ CreateCell”設置,則該塊將在執行該塊時使用Cell的值。
因此,重要的是要記住聲明一個局部變量,該變量在必要時采用類變量的值。
存儲:
- (void) addCallback:(CallBlock_t)B At:(int)at {
//Creates a Callback-Object and passes it the block and adds it to an Array.
}
- (id) initWithBlock:(CallBlock_t)B At:(int)at {
self = [super init];
if(self) {
Block = [B copy]; //Yes, Copy. Not retain.
When = at;
}
return self;
}
此時的陷阱:如果僅保留該塊,則調用函數中的本地塊將超出范圍,並且程序將因“錯誤訪問”而失敗。 復制可以解決此問題。
當然,一旦使用完Block(在回調類的dealloc中),您就需要釋放它,但這是已知的。
我希望這個簡短的解釋可以減輕一些人的痛苦。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.