2012-07-23 2 views
8

Sto scrivendo uno strumento che trarrebbe vantaggio dalla conoscenza di quale classe di istanza è stata dichiarata __weak.Scoperta in fase di esecuzione quale delle variabili di istanza di classe sono dichiarate __basso

Questa informazione deve esistere da qualche parte in fase di esecuzione, ma esiste un modo per accedervi, documentato o altrimenti? (È per uno strumento, quindi non mi interessa tanto rompersi con gli aggiornamenti)

+0

Questa domanda ha attirato la mia attenzione, quindi se non ricevi una risposta, non ti preoccupare, ci sto lavorando –

+0

Ha importanza se l'iVar è 'unsafe_unretained' vs' weak'? Altrimenti, questo mi rende la vita molto più facile. –

+0

forte vs non forte è la distinzione che mi interessa. –

risposta

4

OK, ecco un'implementazione di esempio, utilizzando un'implementazione di oggetto personalizzato, che esegue un controllo rudimentale per vedere se un iVar è debole o no:

BOOL iVarIsWeak(Class cls, Ivar ivar) 
{ 
    id classInstance = [cls new]; 

    // our custom base class properly tracks reference counting, no weird voodoo 
    id refCounter = [CustomBaseClass new]; 

    object_setIvar(classInstance, ivar, refCounter); 

    if ([refCounter refCount] == 2) 
    { 
     return NO; 
    } 

    return YES; 
} 

il codice di cui sopra è pensato per essere utilizzato con ARC abilitato, mentre il seguente codice oggetto personalizzato non è:

@interface CustomBaseClass : NSObject 

+(id) new; 
+(id) alloc; 
-(id) init; 

-(id) retain; 
-(void) release; 
-(id) autorelease; 
-(void) dealloc; 

-(id) description; 

-(unsigned) refCount; 

@end 


// easy way to get sizeof 
struct CustomBaseClassAsStruct { 
    voidPtr isa; 
    unsigned volatile refcount; 
}; 

@implementation CustomBaseClass 
{ 
    unsigned volatile refcount; 
} 

+(id) new 
{ 
    return [[self alloc] init]; 
} 

+(id) alloc 
{ 
    struct CustomBaseClassAsStruct *results = malloc(sizeof(struct CustomBaseClassAsStruct)); 
    results->isa = self; 
    results->refcount = 0; 
    return (id) results; 
} 

-(id) init 
{ 
    [self retain]; 

    return self; 
} 

-(id) retain 
{ 
    ++refcount; 

    return self; 
} 

-(void) release 
{ 
    if (--refcount == 0) 
     [self dealloc]; 
} 

-(id) autorelease 
{ 
    // sample implementation of autorelease 
    dispatch_async(dispatch_get_current_queue(), ^{ 
     [self release]; 
    }); 

    return self; 
} 

-(unsigned) refCount 
{ 
    return refcount; 
} 

-(void) dealloc 
{ 
    free(self); 

    // no call to [super dealloc], we are using custom memory-managment 
} 

@end 

questo funziona solo per Ivars deboli. Con una variabile unsafe_unretained, si otterrà un falso positivo, la mia ipotesi migliore per questo è perché le informazioni __weak vengono salvate in fase di esecuzione mentre le informazioni unsafe_unretained non lo sono.

Spero che questo aiuti!

+0

Interessante. Avevo pensato che il runtime necessitasse solo di informazioni sull'archiviazione per azzerare i riferimenti deboli durante la deallocazione, ma non avevo considerato che object_setIvar ne avrebbe avuto bisogno (anche se ha senso dato che object_setInstanceVariable è bannato sotto ARC). Probabilmente dovrebbe trattare '__unsafe_unretained' in modo simile a' __weak'. Presenterò un bug. –