2013-05-15 5 views

risposta

1

Dopo averlo provato, la risposta è NO.

Ho eseguito il seguente codice sotto l'iOS 6 Simulator, ma sarebbe probabilmente avere lo stesso comportamento con le precedenti iterazioni della fase di esecuzione:

NSObject *test1 = [NSObject new]; 

NSObject __weak *test2 = test1; 

objc_setAssociatedObject(self, "test", test1, OBJC_ASSOCIATION_ASSIGN); 

test1 = nil; 

id test3 = objc_getAssociatedObject(self, "test"); 

Alla fine, test1 e test2 sono pari a zero, e test3 è il puntatore precedentemente memorizzato in test1. L'utilizzo di test3 comporterebbe il tentativo di accedere a un oggetto che era già stato deallocato.

+0

Typo lì dentro? in che modo "test1" è correlato a "test" e "test2"? – Jeff

0

Questo comportamento non è specificato nei documenti o nelle intestazioni come meglio posso dire, quindi è probabile un dettaglio di implementazione su cui non si dovrebbe fare affidamento, anche se si è in grado di discernere qual è il comportamento corrente. Direi che è non azzerato. Ecco perché:

In generale, non è necessario eseguire nil riferimenti in iVars durante -dealloc. Se un oggetto è deallocato, non dovrebbe importare se i suoi iVar fossero azzerati, perché qualsiasi ulteriore accesso dell'oggetto dealloced o dei suoi iVars è, di per sé, un errore di programmazione. In effetti, ho sentito alcuni affermare che è meglio per non cancellare i riferimenti durante -dealloc, perché renderà errati gli accessi più evidenti/esporre i bug prima.

EDIT: Oh, credo di aver letto male la tua domanda. Vuoi "azzerare riferimenti deboli". Lo spazio di archiviazione associato non sembra supportare quelli. Potresti fare una banale lezione di passaggio con un ivar/proprietà contrassegnati come __weak e ottenere lo stesso effetto in questo modo. Un po 'imbarazzante, ma funzionerebbe.

+0

Intendo nel caso che sto guardando, non è un errore se provo ad accedere all'oggetto dopo che è stato deallocato. Se ho un riferimento debole, come un riferimento a un delegato, mi aspetto che possa non esistere più al momento in cui lo invio. – ultramiraculous

26

Come dimostrato ultramiraculous, OBJC_ASSOCIATION_ASSIGN non esegue l'azzeramento di riferimento debole e si rischia di accedere a un oggetto deallocato. Ma è abbastanza facile da implementare te stesso. Hai solo bisogno di una semplice classe per avvolgere un oggetto con un riferimento debole:

@interface WeakObjectContainer : NSObject 
@property (nonatomic, readonly, weak) id object; 
@end 

@implementation WeakObjectContainer 
- (instancetype) initWithObject:(id)object 
{ 
    if (!(self = [super init])) 
     return nil; 

    _object = object; 

    return self; 
} 
@end 

allora si deve associare il WeakObjectContainer come OBJC_ASSOCIATION_RETAIN (_NONATOMIC):

objc_setAssociatedObject(self, &MyKey, [[WeakObjectContainer alloc] initWithObject:object], OBJC_ASSOCIATION_RETAIN_NONATOMIC); 

e utilizzare la proprietà object per accedervi in per ottenere un riferimento debole azzeramento:

id object = [objc_getAssociatedObject(self, &MyKey) object]; 
+1

Hehe! Approccio davvero intelligente. Lo adoro! Lo terrò a mente. – MonsieurDart

+0

Perché non usare solo NSValue :: valueWithNonretainedObject:? – AlexDenisov

+2

Poiché '- [NSValue nonretainedObjectValue]' non restituisce un oggetto * weak * e pertanto non esegue l'azzeramento del riferimento debole. – 0xced

4

una possibilità più simile a WeakObjectContainer:

0.123.
- (id)weakObject { 
    id (^block)() = objc_getAssociatedObject(self, @selector(weakObject)); 
    return (block ? block() : nil); 
} 

- (void)setWeakObject:(id)object { 
    id __weak weakObject = object; 
    id (^block)() = ^{ return weakObject; }; 
    objc_setAssociatedObject(self, @selector(weakObject), 
          block, OBJC_ASSOCIATION_COPY); 
}