iphone - Matriz no retenida para delegados
nfc iphone 6 (10)
En un proyecto Cocoa Touch, necesito una clase específica para tener no solo un único objeto delegado, sino muchos de ellos.
Parece que debería crear una NSArray para estos delegados; el problema es que NSArray mantendría a todos estos delegados retenidos, lo que no debería (por objeto de la convención no debería retener a sus delegados)
¿Debo escribir mi propia clase de matriz para evitar la retención o hay métodos más simples? ¡Gracias!
¿Qué hay de almacenar en la matriz o diccionario?
__weak typeof(pointer) weakPointer = pointer;
Encontré algunas piezas de código del proyecto Three20 sobre este tema, espero que esto ayude ...
NSMutableArray* TTCreateNonRetainingArray() {
CFArrayCallBacks callbacks = kCFTypeArrayCallBacks;
callbacks.retain = TTRetainNoOp;
callbacks.release = TTReleaseNoOp;
return (NSMutableArray*)CFArrayCreateMutable(nil, 0, &callbacks);
}
NSMutableDictionary* TTCreateNonRetainingDictionary() {
CFDictionaryKeyCallBacks keyCallbacks = kCFTypeDictionaryKeyCallBacks;
CFDictionaryValueCallBacks callbacks = kCFTypeDictionaryValueCallBacks;
callbacks.retain = TTRetainNoOp;
callbacks.release = TTReleaseNoOp;
return (NSMutableDictionary*)CFDictionaryCreateMutable(nil, 0, &keyCallbacks, &callbacks);
}
Encontré este poco de código hace un tiempo (no recuerdo a quién atribuirlo).
Es bastante ingenioso, usar una Categoría para permitir la creación de una matriz mutable que no retiene / libera al respaldarla con un CFArray
con devoluciones de llamada adecuadas.
@implementation NSMutableArray (WeakReferences)
+ (id)mutableArrayUsingWeakReferences {
return [self mutableArrayUsingWeakReferencesWithCapacity:0];
}
+ (id)mutableArrayUsingWeakReferencesWithCapacity:(NSUInteger)capacity {
CFArrayCallBacks callbacks = {0, NULL, NULL, CFCopyDescription, CFEqual};
// We create a weak reference array
return (id)(CFArrayCreateMutable(0, capacity, &callbacks));
}
@end
EDITAR Encontró el artículo original: http://ofcodeandmen.poltras.com
Encontré una biblioteca de código abierto llamada XMPPFramewrok
Hay una solución de delegado de multidifusión en el proyecto.
https://github.com/robbiehanson/XMPPFramework/wiki/MulticastDelegate
Este de NIMBUS sería más simple:
NSMutableArray* NICreateNonRetainingMutableArray(void) {
return (NSMutableArray *)CFArrayCreateMutable(nil, 0, nil);
}
NSMutableDictionary* NICreateNonRetainingMutableDictionary(void) {
return (NSMutableDictionary *)CFDictionaryCreateMutable(nil, 0, nil, nil);
}
NSMutableSet* NICreateNonRetainingMutableSet(void) {
return (NSMutableSet *)CFSetCreateMutable(nil, 0, nil);
}
No quieres hacer esto! Cocoa Touch tiene varios conceptos para enviar eventos, debe usar el concepto adecuado para cada caso.
- Acción de destino: para los controles de IU, como presionar botones. Un remitente, cero o más receptores.
- Delegados: Sólo para un remitente y un destinatario.
- Notificación: Para un remitente, y cero o más receptores.
- KVO: Más fino que las notificaciones.
Lo que debes hacer es mirar cómo usar la clase NSNotificationCenter
. Esta es la forma correcta de enviar una notificación que tenga más de un receptor.
Palabra clave: NSHashTable
, búsqueda en documentaciones.
Presento una limitación importante de una de las respuestas anteriores, junto con una explicación y una mejora.
Johnmph sugirió usar [NSValue valueWithNonretainedObject:]
.
Tenga en cuenta que cuando hace esto, su referencia actúa no como __weak
, sino como __unsafe_unretained
mientras está dentro del objeto NSValue. Más específicamente, cuando intentes recuperar tu referencia (usando [myNSValue nonretainedObjectValue]), tu aplicación se bloqueará con una señal EXC_BAD_ACCESS si el objeto se ha desasignado antes de esa hora.
En otras palabras, la referencia débil no se establece automáticamente en cero mientras está dentro del objeto NSValue
. Esto me tomó un montón de horas para averiguar. He resuelto este problema creando una clase simple con solo una propiedad de referencia débil.
¡Más bellamente, al usar NSProxy
, podemos tratar el objeto envoltorio por completo como si fuera el objeto contenido en sí mismo!
// WeakRef.h
@interface WeakRef : NSProxy
@property (weak) id ref;
- (id)initWithObject:(id)object;
@end
// WeakRef.m
@implementation WeakRef
- (id)initWithObject:(id)object
{
self.ref = object;
return self;
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
invocation.target = self.ref;
[invocation invoke];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
return [self.ref methodSignatureForSelector:sel];
}
@end
Verifique la documentación del método NSValue valueWithNonretainedObject:
Este método es útil para evitar que un objeto se retenga cuando se agrega a un objeto de colección (como una instancia de NSArray o NSDictionary).
Yo sugeriría no luchar contra el marco y usar NSPointerArray con NSPointerFunctionsWeakMemory
NSPointerFunctionOption
esta manera:
NSPointerArray *weakReferencingArray = [NSPointerArray pointerArrayWithOptions:NSPointerFunctionsWeakMemory];
// NSPointerFunctionsWeakMemory - Uses weak read and write barriers
// appropriate for ARC or GC. Using NSPointerFunctionsWeakMemory
// object references will turn to NULL on last release.
Me sirvió bien en los escenarios, donde tuve que diseñar una matriz de delegados, que se auto-nula las referencias.