Parece que usted desea comunicarse con una clase existente que está diseñado para tomar una delegar objeto Hay una serie de enfoques, que incluyen:
- utilizando una categoría para agregar variantes basadas en bloques de los métodos apropiados;
- utiliza una clase derivada para agregar las variantes basadas en bloques; y
- escribe una clase que implemente el protocolo y llame a tus bloques.
Aquí hay una manera de hacerlo (3). En primer lugar vamos a suponer que su SomeObject es:
@protocol SomeObjectDelegate
@required
- (void)stuffDone:(id)anObject;
- (void)stuffFailed;
@end
@interface SomeObject : NSObject
{
}
+ (void) testCallback:(id<SomeObjectDelegate>)delegate;
@end
@implementation SomeObject
+ (void) testCallback:(id<SomeObjectDelegate>)delegate
{
[delegate stuffDone:[NSNumber numberWithInt:42]];
[delegate stuffFailed];
}
@end
por lo que tienen alguna manera de probar - que tendrá una SomeObject real.
Ahora definir una clase que implementa el protocolo y llama a sus bloques suministrados:
#import "SomeObject.h"
typedef void (^StuffDoneBlock)(id anObject);
typedef void (^StuffFailedBlock)();
@interface SomeObjectBlockDelegate : NSObject<SomeObjectDelegate>
{
StuffDoneBlock stuffDoneCallback;
StuffFailedBlock stuffFailedCallback;
}
- (id) initWithOnDone:(StuffDoneBlock)done andOnFail:(StuffFailedBlock)fail;
- (void)dealloc;
+ (SomeObjectBlockDelegate *) someObjectBlockDelegateWithOnDone:(StuffDoneBlock)done andOnFail:(StuffFailedBlock)fail;
// protocol
- (void)stuffDone:(id)anObject;
- (void)stuffFailed;
@end
Esta clase guarda los bloques que entran y los llama en respuesta a las devoluciones de llamada de protocolo. La implementación es sencilla:
@implementation SomeObjectBlockDelegate
- (id) initWithOnDone:(StuffDoneBlock)done andOnFail:(StuffFailedBlock)fail
{
if (self = [super init])
{
// copy blocks onto heap
stuffDoneCallback = Block_copy(done);
stuffFailedCallback = Block_copy(fail);
}
return self;
}
- (void)dealloc
{
Block_release(stuffDoneCallback);
Block_release(stuffFailedCallback);
[super dealloc];
}
+ (SomeObjectBlockDelegate *) someObjectBlockDelegateWithOnDone:(StuffDoneBlock)done andOnFail:(StuffFailedBlock)fail
{
return (SomeObjectBlockDelegate *)[[[SomeObjectBlockDelegate alloc] initWithOnDone:done andOnFail:fail] autorelease];
}
// protocol
- (void)stuffDone:(id)anObject
{
stuffDoneCallback(anObject);
}
- (void)stuffFailed
{
stuffFailedCallback();
}
@end
La única cosa que hay que recordar es Block_copy() los bloques cuando se inicializa y para Block_release() más adelante - esto se debe a que los bloques están pila asignados y su objeto pueden sobrevivir a su creador marco de pila; Block_copy() crea una copia en el montón.
Ahora se puede todo, un método basado en el delegado de pasarlo bloques:
[SomeObject testCallback:[SomeObjectBlockDelegate
someObjectBlockDelegateWithOnDone:^(id anObject) { NSLog(@"Done: %@", anObject); }
andOnFail:^{ NSLog(@"Failed"); }
]
];
Puede utilizar esta técnica para envolver los bloques para cualquier protocolo.
ARC Adición
En respuesta al comentario: hacer de este arco compatibles simplemente eliminar las llamadas a Block_copy()
dejando asignaciones directas:
stuffDoneCallback = done;
stuffFailedCallback = fail;
y retire el método dealloc
. También puede cambiar Blockcopy
a copy
, es decir, stuffDoneCallback = [done copy];
, y esto es lo que podría suponer que es necesario al leer la documentación de ARC. Sin embargo, no es como la asignación a una variable fuerte que hace que ARC retenga el valor asignado, y al retener un bloque de pila lo copia al montón. Por lo tanto, el código ARC generado produce los mismos resultados con o sin el copy
.
¿Puede explicar esta parte con ARC? stuffDoneCallback = Block_copy (hecho); stuffFailedCallback = Block_copy (error); Me dice que necesita un puente de yeso. – zeiteisen
@zeiteisen - Buena pregunta. Probablemente ya sepa la respuesta, disculpe que nunca vi el comentario. Pero para futuros visitantes, he agregado un apéndice. – CRD