用块替换委托方法的最佳技术 [英] Best Technique for Replacing Delegate Methods with Blocks
问题描述
我正在寻找创建一个类别,用许多简单的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:
-
明确标记它实现的委托如下:
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屋!