Matriz no retenida para delegates

En un proyecto Cocoa Touch, necesito una clase específica para tener no solo un solo objeto delegado, sino muchos de ellos.

Parece que debería crear un NSArray para estos delegates; el problema es que NSArray tendría todos estos delegates retenidos, lo que no debería (por convención los objetos no deberían retener a sus delegates).

¿Debo escribir mi propia clase de arreglo para evitar retener o hay métodos más simples? ¡Gracias!

Encontré este fragmento de código hace un rato (no recuerdo a quién atribuirlo).

Es bastante ingenioso, el uso de una categoría para permitir la creación de una matriz mutable que no conserva / liberación al respaldarlo 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 Encontrado el artículo original: http://ofcodeandmen.poltras.com

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 no actúa como __weak , sino más bien como __unsafe_unretained mientras está dentro del objeto NSValue. Más específicamente, cuando intenta recuperar su referencia (utilizando [myNSValue nonretainedObjectValue]), su aplicación se bloqueará con una señal EXC_BAD_ACCESS si el objeto ha sido desasignado antes de ese momento.

En otras palabras, la referencia débil no se establece automáticamente en nil mientras se encuentra dentro del objeto NSValue . Esto me tomó un montón de horas para averiguarlo. He solucionado esto creando una clase simple con solo una propiedad de ref 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 valor NSValueCon el método Sin retención:

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).

¡No quieres hacer esto! Cocoa Touch tiene varios conceptos para enviar eventos, debe usar el concepto adecuado para cada caso.

  1. Acción de destino: para controles de IU, como pulsaciones de botones. Un emisor, cero o más receptores.
  2. Delegados: solo para un emisor y un receptor.
  3. Notificación: para un emisor, y cero o más receptores.
  4. KVO: Más fino que las notificaciones.

Lo que debes hacer es ver cómo usar la clase NSNotificationCenter . Esta es la forma correcta de enviar una notificación que tenga más de un receptor.

Sugeriría no-luchar-el-marco y usar NSPointerArray con NSPointerFunctionsWeakMemory NSPointerFunctionOption así:

 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 delegates, cuyas referencias auto-NULL.

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); } 

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); } 

Palabra clave: NSHashTable , búsqueda en documentaciones.

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

¿Qué pasa con el almacenamiento en la matriz o el diccionario?

 __weak typeof(pointer) weakPointer = pointer;