2010-05-14 10 views
10

Ho un pezzo di codice Objective-C, che è simile al seguente:Come posso risolvere questo avvertimento di clang: "L'oggetto con +0 conserva i conteggi restituiti al chiamante in cui è previsto il conteggio di mantenimento +1 (proprietario)"?

- (NSString *)copyData:(NSData *)data 
{ 
    NSString *path = [[[self outputDirectory] stringByAppendingPathComponent:@"archive"] stringByAppendingPathExtension:@"zip"]; 
    NSLog(@"Copying data to %@", path); 
    [data writeToFile:path atomically:NO]; 
    return path; 
} 

Il codice viene chiamato da un inizializzatore che assomiglia a questo:

- (id)initWithData:(NSData *)data 
{ 
    if ((self = [super init]) != nil) { 
     NSString *path = [self copyData:data];  // Line 41 (referenced in warning, shown below) 
     return [self initWithContentsOfFile:path]; 
    } 
    return self; 
} 

Quando si esegue l'analizzatore statico clang, ottengo le seguenti avvertenze per la path variabile:

perdita potenziale di un oggetto allocato sulla linea 41 e memorizzati in 'percorso'

Oggetto con +0 mantenere i conteggi restituito al chiamante in cui uno (possedere) mantenere il conteggio è previsto

Sono confuso. La mia comprensione è che stringByAppendingPathComponent dovrebbe restituire una stringa autoreleased, quindi dovrebbe avere una rete conservare conteggio di 0. (Ovviamente io non voglio di conservarlo.)

Ho cercato alterare copyData: per tornare il seguente, ma non ha eliminato l'avviso:

return [[path retain] autorelease]; 

Quindi qual è l'accordo con questo avviso?

risposta

15

Ho il sospetto che stia solo rilevando un metodo con il prefisso copy e contrassegnandolo come qualcosa che dovrebbe restituire qualcosa che il chiamante possiede, perché pensa di seguire le convenzioni di denominazione di Cocoa.

Nel tuo caso, ovviamente, ti stai riferendo a file e quant'altro, quindi è un avvertimento ignorante. Se cambi il nome del tuo metodo, a qualcosa come saveData:, invece, scommetto che l'avvertimento sparirà.

4

Poiché il metodo ha il nome copy in esso, l'analizzatore si aspetta che l'oggetto restituito abbia un conteggio di ritenzione +1, in base allo Memory Management Guide.

4

No, non è corretto; a meno che il metodo non contenga "alloc", "copy", "new" o una delle altre parole chiave che implica che l'oggetto sia di proprietà dell'invoker, il metodo restituisce un oggetto autoreleased o altrimenti gestito, quindi stringByAppendingPathComponent restituisce una stringa autorizzata .

Inoltre, il metodo "copyData" contiene la parola "copy", il che implica che il risultato debba essere posseduto (e rilasciato) dal chiamante. Tuttavia, il risultato che hai restituito è stato autorizzato automaticamente, quindi il messaggio di errore che ti sta dando. Se si desidera correggere l'errore, non autorelease. Ovvero:

return [path retain] 

Ovviamente ciò implica che i chiamanti della funzione devono rilasciarlo. In alternativa, puoi cambiare il nome della tua funzione in modo che sia conforme alle linee guida sulla gestione della memoria.

Il nome "copyData", IMHO, non è comunque intuitivo. Ti suggerisco di rinominare la tua funzione in "pathToSavedDataWithData" o qualcosa di simile. Qualcosa che dice quello che effettivamente sta facendo.

9

Inoltre, per le volte in cui si desidera nominare un metodo con 'copia' o qualcosa del genere, indipendentemente dalle linee guida di gestione della memoria Cocoa, copiare è il nome migliore per il metodo, è possibile annotare la declairazione del metodo con NS_RETURNS_NOT_RETAINED e quindi Clang non ti darà un avvertimento. Quindi:

// Copies data from data to string; does not follow the copy rule 
- (NSString*)copyData:(NSData*)data NS_RETURNS_NOT_RETAINED; 
+1

Questa risposta ha rimosso così tanti avvisi errati dal mio progetto! –

0

ho intenzione di prendere una pugnalata a questo e immaginare che si otterrebbe lo stesso messaggio di errore esatto, se non il nome della vostra routine è iniziato con "copia ..." o no . Ho appena finito in uno scenario simile e "copiare" non faceva parte del nome della routine che stavo chiamando. Clang stava dando il messaggio di errore semplicemente perché stavo restituendo un oggetto autoreleased, una situazione pericolosa. Facendo il trucco

return [path retain] 

alla fine come raccomandato da Michael si prese cura del problema.

+0

Whoops! Posso commentare la mia risposta? Si scopre che il nome della mia routine è iniziato con "nuovo ...", quindi sembra che fossi un po 'frettoloso. Lo so meglio ora :-) – hkatz