2012-01-05 19 views
20

Vorrei memorizzare un riferimento debole di azzeramento a un oggetto in un NSDictionary. Si tratta di un riferimento a un genitore NSDictionary, quindi è possibile eseguire la scansione di una grande struttura senza effettuare ricerche.Oggetto debole in un NSDictionary?

Non riesco a utilizzare __weak qui; anche se il mio riferimento locale è debole, lo NSDictionary memorizzerà un riferimento forte all'oggetto a cui è stato fatto un debole riferimento. E, ovviamente, NSDictionary non può avere oggetti nil.

Sono su iOS, non su Mac, quindi NSHashTable non è disponibile. E voglio solo un oggetto per essere debole; il resto dovrebbe essere ancora forte.

(ho intenzione di pubblicare la mia risposta, così ho qualcosa da contrassegnare come accettata se non c'è risposta migliore. Ma sto sperando che qualcuno ha una risposta migliore.)

+0

Ho creato [questo] (https://gist.github.com/firelizzard18/6326536) per essere un dizionario che memorizza oggetti come effettivamente azzerando riferimenti deboli. Potrebbe essere modificato (e ripulito) per servire ai tuoi scopi. –

risposta

35

In iOS 6+ è possibile utilizzare NSMapTable e scegliere se si desidera che gli oggetti e/o le chiavi siano deboli o forti.

+2

Chiaramente la migliore risposta per oggi e per il futuro. Grazie. –

+0

Hai avuto il mio voto – Carina

+3

NSMapTable potrebbe non comportarsi come previsto: http://cocoamine.net/blog/2013/12/13/nsmaptable-and-zeroing-weak-references/ – nehz

14

ho optato per la definizione una classe di "contenitore" con un solo membro, in questo modo:

@interface Parent : NSObject 
@property (nonatomic, weak) id parent; 
@end 

@implementation Parent 

@synthesize parent = _parent; 

- (id)initWithParent: (id)parent; 
{ 
    if ((self = [super init])) { 
     _parent = parent; 
    } 
    return self; 
} 
@end 

e di utilizzarlo:

id parentRef = [[Parent alloc] initWithParent: parent]; 
[newElement setObject: parentRef forKey: ParentKey]; 

penso che questo lavoro per me, ma sembra pazzesco che non esiste un modo migliore di integrarsi in Foundation.

+0

Suona come l'unica soluzione per me - è così che avrei fatto anche io. O un 'NSValue', ma questo non si azzererebbe. – mattjgalloway

+1

Ho lo stesso problema e ho anche pensato a un contenitore, non ho ancora provato, ma sto cercando di fare qualcosa di simile a quello che fai con block 'id __weak weakObject = strongObject; [optionDict setValue: [NSValue valueWithNonretainedObject: tmpObject] forKey: key]; 'ancora bisogno di capire se funziona. – Andrea

+1

Vecchio commento, ma lo aggiungerò per i nuovi visitatori. Quello che dice Andrea non funzionerà, il dizionario manterrebbe comunque l'oggetto. – Emanuel

6

Esiste un modo integrato; basta usare:

[array addObject:[NSValue valueWithNonretainedObject:object]]; 

Poi per accedere all'oggetto in seguito, l'uso:

id object = [[array objectAtIndex:i] nonretainedObjectValue]; 

Se il valore è stato rilasciato in quanto si è aggiunto poi "oggetto" sarà un puntatore non valido sotto iOS 4.x e (presumo) sarà nil sotto 5.x con ARC abilitato.

EDIT: la mia ipotesi era sbagliata: non è debole sotto ARC (vedi la discussione sotto).

+3

No, è un puntatore pendente. Ma grazie per l'idea. :) –

+0

Tuttavia, il puntatore pendente non dovrebbe mai essere accessibile poiché il tuo oggetto è vicino alla morte in quel momento. Quindi l'accesso al genitore qui dovrebbe essere comunque un bug, che in questo caso non è nascosto da niling out. – Eiko

+1

@Eiko, ti sbagli. È un caso comune per il modello di osservatore. –