用块替换委托方法的最佳技术 [英] Best Technique for Replacing Delegate Methods with Blocks

查看:84
本文介绍了用块替换委托方法的最佳技术的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找创建一个类别,用许多简单的iOS API替换委托方法和回调块。与NSURLConnection上的sendAsyc块类似。有两种技术是无泄漏的,似乎工作正常。每个人的利弊是什么?有没有更好的方法?

I'm looking to create a category to replace delegate methods with callbacks blocks for a lot of the simple iOS APIs. Similar to the sendAsyc block on NSURLConnection. There are 2 techniques that are leak free and seem to work fine. What are the pros/cons about each? Is there a better way?

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

Option 1. Use a category to implement the delegate's callback method on NSObject with the external callback block scoped.

// 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上,似乎它可能会导致任何其他类尝试使用标准委托方法的问题。但它使对象保持活动状态并返回回调而没有我发现的任何泄漏。

This adds a lot of methods on the NSObject and seems like it could cause issues with any other class trying to use the standard delegate method. But it keeps the block alive with the object and returns the callback without any leaks that I've found.

选项2创建一个轻量级类来包含块,动态地将它与类关联,这样它将保留在堆中并在回调完成时将其删除。

Option 2. Create an light-weight class to contain the block, dynamicly associate it with the class so it will stay in the heap and remove it when the callback is complete.

// 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之上添加任何东西,事情稍微分开。它通过函数的地址附加到实例。

I like that this doesn't add anything on top of NSObject and things are a little more separated. It's attaching to the instance via the address of the function.

推荐答案

我遇到了类似的问题并选择了你的选项2,但是2个小的补充:

I had a similar problem and chose your option 2, but with the 2 small additions:


  1. 明确标记它实现的委托如下:

  1. Explicitly marking the delegate it implements like this:

@interface __DelegateBlock:NSObject <BlocksDelegate>


  • 在调用之前检查以确保回调不是nil:

  • Check to ensure the callback is not nil before calling:

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


  • 这篇关于用块替换委托方法的最佳技术的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆