Я ищу, чтобы создать категорию, чтобы заменить методы делегирования блоками обратных вызовов для множества простых API-интерфейсов iOS. Подобно блоку sendAsyc для NSURLConnection. Есть 2 метода, которые не содержат утечек и, похоже, работают нормально. Каковы плюсы и минусы каждого из них? Есть ли способ лучше?Лучшая техника для замены методов делегатов с помощью блоков
Вариант 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, и вещи немного более разделены. Он прикрепляется к экземпляру через адрес функции.
Вариант 3: Подкласс 'UIAlertView'. –
Справа. Работа подкласса. Но он будет загроможден и имеет меньший код повторного использования, когда я подклассифицирую каждый API-интерфейс Apple, чтобы добавить один вызов метода. Кроме того, я помещаю все эти API в один класс, поэтому легко импортировать и использовать категории, чтобы вызов метода был более чистым и ближе к API-интерфейсам Apple. Если заканчивается хороший общий способ удержания и возврата блока, тогда этот код может быть повторно использован с небольшими изменениями, когда мне нужно добавить еще один асинхронный блочный метод к API-интерфейсу Apple. – puppybits
Хорошо, я вижу. Это довольно серьезная задача. Я просто пытался спасти вас от врезания во время работы. –