用块replace委托方法的最佳技术

我正在寻找创build一个类别来取代委托方法与许多简单的iOS API的callback块。 类似于NSURLConnection上的sendAsyc块。 有2种技术是无泄漏的,似乎工作正常。 各有什么优点/缺点? 有没有更好的办法?

选项1.使用一个类别在NSObject上实现委托的callback方法,并将外部callback块作用域。

// Add category on NSObject to respond to the delegate @interface NSObject(BlocksDelegate) - (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex; @end @implementation NSObject(BlocksDelegate) - (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { // Self is scoped to the block that was copied void(^callback)(NSInteger) = (id)self; // Call the callback passed if callback(buttonIndex); [self release]; } @end // Alert View Category @implementation UIAlertView (BlocksDelegate) + (id) alertWithTitle:(NSString*)title message:(NSString*)message clickedBlock:(void(^)(NSInteger))buttonIndexClickedBlock cancelButtonTitle:(NSString*)cancelButtonTitle otherButtonTitles:(NSString*)otherButtonTitles { // Copy block passed in to the Heap and will stay alive with the UIAlertView UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:[buttonIndexClickedBlock copy] cancelButtonTitle:cancelButtonTitle otherButtonTitles:otherButtonTitles, nil]; // Display the alert [alert show]; // Autorelease the alert return [alert autorelease]; } @end 

这在NSObject上添加了很多方法,似乎可能会导致任何其他类尝试使用标准委托方法的问题。 但它保持块与对象一起活着,并返回callback没有任何泄漏,我已经find。


选项2.创build一个轻量级的类来包含该块,将其与该类dynamic关联,以便将其保留在堆中,并在callback完成时将其删除。

 // Generic Block Delegate @interface __DelegateBlock:NSObject typedef void (^HeapBlock)(NSInteger); @property (nonatomic, copy) HeapBlock callbackBlock; @end @implementation __DelegateBlock @synthesize callbackBlock; - (id) initWithBlock:(void(^)(NSInteger))callback { // Init and copy Callback Block to the heap (@see accessor) if (self = [super init]) [self setCallbackBlock:callback]; return [self autorelease]; } - (void) dealloc { // Release the block [callbackBlock release], callbackBlock = nil; [super dealloc]; } - (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { // Return the result to the callback callbackBlock(buttonIndex); // Detach the block delegate, will decrement retain count SEL key = @selector(alertWithTitle:message:clickedBlock:cancelButtonTitle:otherButtonTitles:); objc_setAssociatedObject(alertView, key, nil, OBJC_ASSOCIATION_RETAIN); key = nil; // Release the Alert [alertView release]; } @end @implementation UIAlertView (BlocksDelegate) + (id) alertWithTitle:(NSString*)title message:(NSString*)message clickedBlock:(void(^)(NSInteger))buttonIndexClickedBlock cancelButtonTitle:(NSString*)cancelButtonTitle otherButtonTitles:(NSString*)otherButtonTitles { // Create class to hold delegatee and copy block to heap DelegateBlock *delegatee = [[__DelegateBlock alloc] initWithBlock:buttonIndexClickedBlock]; [[delegatee retain] autorelease]; // Create delegater UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:delegatee cancelButtonTitle:cancelButtonTitle otherButtonTitles:otherButtonTitles, nil]; // Attach the Delegate Block class to the Alert View, increase the retain count objc_setAssociatedObject(alert, _cmd, delegatee, OBJC_ASSOCIATION_RETAIN); // Display the alert [alert show]; return alert; } @end 

我喜欢这不会添加任何东西的顶部NSObject和事情是多一点分开。 它通过函数的地址附加到实例。

我有一个类似的问题,并select了你的select2,但有两个小的增加:

  1. 显式标记它实现的代理如下所示:

     @interface __DelegateBlock:NSObject <BlocksDelegate> 
  2. 调用前确保callback不为零:

     if (callbackBlock != nil) { callbackBlock(buttonIndex); } 

以下是我所做的:

 typedef void(^EmptyBlockType)(); @interface YUYesNoListener : NSObject <UIAlertViewDelegate> @property (nonatomic, retain) EmptyBlockType yesBlock; @property (nonatomic, retain) EmptyBlockType noBlock; + (void) yesNoWithTitle:(NSString*)title message:(NSString*)message yesBlock:(EmptyBlockType)yesBlock noBlock:(EmptyBlockType)noBlock; @end @implementation YUYesNoListener @synthesize yesBlock = _yesBlock; @synthesize noBlock = _noBlock; - (id) initWithYesBlock:(EmptyBlockType)yesBlock noBlock:(EmptyBlockType)noBlock { self = [super init]; if (self) { self.yesBlock = [[yesBlock copy] autorelease]; self.noBlock = [[noBlock copy] autorelease]; } return self; } - (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { if (buttonIndex == 0 && self.noBlock) self.noBlock(); else if (buttonIndex == 1 && self.yesBlock) self.yesBlock(); [_yesBlock release]; [_noBlock release]; [alertView release]; [self release]; } - (void) alertViewCancel:(UIAlertView *)alertView { if (self.noBlock) self.noBlock(); [_yesBlock release]; [_noBlock release]; [alertView release]; [self release]; } + (void) yesNoWithTitle:(NSString*)title message:(NSString*)message yesBlock:(EmptyBlockType)yesBlock noBlock:(EmptyBlockType)noBlock { YUYesNoListener* yesNoListener = [[YUYesNoListener alloc] initWithYesBlock:yesBlock noBlock:noBlock]; [[[UIAlertView alloc] initWithTitle:title message:message delegate:yesNoListener cancelButtonTitle:@"No" otherButtonTitles:@"Yes", nil] show]; } @end