Estoy buscando crear una categoría para reemplazar los métodos de delegado con bloques de devolución de llamada para muchas de las API de iOS simples. Similar al bloque sendAsyc en NSURLConnection. Hay 2 técnicas que no tienen fugas y parecen funcionar bien. ¿Cuáles son los pros/contra de cada uno? ¿Hay una mejor manera?Mejor técnica para reemplazar métodos de delegado con bloques
Opción 1. Use una categoría para implementar el método de devolución de llamada del delegado en NSObject con el bloque de devolución de llamada externa con ámbito.
// 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
Esto añade una gran cantidad de métodos en el NSObject y parece que podría causar problemas con cualquier otra clase tratando de utilizar el método de delegado estándar. Pero mantiene el bloque vivo con el objeto y devuelve la devolución de llamada sin ninguna filtración que he encontrado.
Opción 2. Crear una clase de peso ligero para contener el bloque, dynamicly asociarlo con la clase para que permanezca en el montón y retirarlo cuando la devolución de llamada se ha completado.
// 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
me gusta que esto no aporta nada en la parte superior de NSObject y las cosas son un poco más separados. Se adjunta a la instancia a través de la dirección de la función.
Opción 3: Subclase 'UIAlertView'. –
Derecha. Trabajos de subclases Pero estará desordenado y tendrá menos código reutilizable cuando estoy subclasificando cada API de Apple para agregar una llamada a un método. Además, estoy colocando todas estas API en una sola clase para que sea fácil de importar y usar categorías, lo que permite que la llamada al método sea más limpia y más cercana a las API de Apple. Si termina siendo una buena manera genérica de mantener y devolver el bloque, entonces ese código puede reutilizarse con pequeños cambios cada vez que necesito agregar un método de bloque asíncrono a una API de Apple. – puppybits
Ok, ya veo. Eso es toda una empresa. Solo estaba tratando de salvarte de perder el tiempo de ejecución. –