2011-12-27 36 views
9

我在創建一個類別,用很多簡單的iOS API的回調塊替換委託方法。類似於NSURLConnection上的sendAsyc塊。有兩種技術是無泄漏的,似乎工作正常。每個人有什麼優點/缺點?有沒有更好的辦法?用塊替換委託方法的最佳方法

選項1.使用一個類別在NSObject上實現委託的回調方法,並將外部回調塊作用域。

// 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上增加了很多方法,似乎它可能會導致任何其他類嘗試使用標準委託方法的問題。但它使塊保持與對象一起活動,並返回回調而沒有發現任何泄漏。


選項2.創建輕量類以包含塊,動態地將其與類關聯所以它會留在堆和回調完成時將其刪除。

// 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中的頂部添加任何東西,事情多一點分開。它通過函數的地址附加到實例。

+0

方案3:子類'UIAlertView'。 – 2011-12-27 20:54:31

+0

對。子類化作品。但是,爲了添加一個方法調用,我將每個蘋果API進行子類化時,它會變得雜亂無章並且可重用代碼更少。此外,我將所有這些API放在一個類中,因此很容易導入和使用類別,這樣方法調用就可以更清晰,更接近Apple API。如果最終成爲一個很好的通用方法來保存並返回塊,那麼無論何時我需要將另一個異步塊方法添加到Apple API時,該代碼都可以重複使用,並進行較小的更改。 – puppybits 2011-12-28 15:11:47

+0

好的,我明白了。這是一項非常重要的任務。我只是試圖讓你免受運行時間的影響。 – 2011-12-28 19:51:27

回答

2

我也有類似的問題,並選擇您的選項2,但與2個小的補充:

  1. 明確標示它實現這樣的委託:

    @interface __DelegateBlock:NSObject <BlocksDelegate> 
    
  2. 檢查,以確保回調不無調用之前:

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

是的,經過幾天的燉過。選項2真的好多了。你的提示很好,清理起來好一點。謝謝。 – puppybits 2012-01-08 15:19:26

0

這裏就是我所做的:

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