Perché ARC mantiene gli argomenti del metodo?

Durante la compilazione con ARC, gli argomenti del metodo spesso sembrano essere mantenuti all’inizio del metodo e rilasciati alla fine. Questa coppia di ritenzione / rilascio sembra superflua e contraddice l’idea che ARC “produce il codice che avresti comunque scritto”. Nessuno in quei giorni oscuri pre-ARC ha eseguito un ulteriore ritouch / rilascio su tutti gli argomenti del metodo solo per essere sicuri, vero?

Prendere in considerazione:

@interface Test : NSObject @end @implementation Test - (void)testARC:(NSString *)s { [s length]; // no extra retain/release here. } - (void)testARC2:(NSString *)s { // ARC inserts [s retain] [s length]; [s length]; // ARC inserts [s release] } - (void)testARC3:(__unsafe_unretained NSString *)s { // no retain -- we used __unsafe_unretained [s length]; [s length]; // no release -- we used __unsafe_unretained } @end 

Quando compilato con Xcode 4.3.2 in modalità di rilascio, l’assembly (tale che sono in grado di capirlo) conteneva le chiamate a objc_retain e objc_release all’inizio e alla fine del secondo metodo. Cosa sta succedendo?

Questo non è un problema enorme, ma questo traffico extra di mantenimento / rilascio appare quando si utilizzano gli strumenti per profilare il codice sensibile alle prestazioni. Sembra che tu possa decorare gli argomenti del metodo con __unsafe_unretained per evitare questo mantenimento / rilascio extra, come ho fatto nel terzo esempio, ma farlo sembra piuttosto disgustoso.

Vedi questa risposta dalla mailing list in lingua Objc:

Quando il compilatore non sa nulla del comportamento di gestione della memoria di una funzione o di un metodo (e questo accade molto), allora il compilatore deve assumere:

1) Che la funzione o il metodo possa completamente riorganizzare o sostituire l’intero grafico dell’object dell’applicazione (probabilmente non lo farà, ma potrebbe). 2) Che il chiamante potrebbe essere un codice conteggio di riferimento manuale, e quindi la durata dei parametri passati non è realisticamente conoscibile.

Dato # 1 e # 2; e dato che ARC non deve mai consentire a un object di essere deallocato prematuramente, allora questi due presupposti costringono il compilatore a conservare gli oggetti passati più spesso.

Penso che il problema principale sia che il corpo del tuo metodo potrebbe portare alla pubblicazione degli argomenti, in modo che ARC debba agire in modo difensivo e conservarli:

 - (void) processItems { [self setItems:[NSArray arrayWithObject:[NSNumber numberWithInt:0]]]; [self doSomethingSillyWith:[items lastObject]]; } - (void) doSomethingSillyWith: (id) foo { [self setItems:nil]; NSLog(@"%@", foo); // if ARC did not retain foo, you could be in trouble } 

Questo potrebbe anche essere il motivo per cui non vedi la conservazione extra quando c’è solo una singola chiamata nel tuo metodo.

Il passaggio come parametro non aumenta, in generale, il conteggio dei ritiri. Tuttavia, se lo passi a qualcosa come NSThread , è specificamente documentato che manterrà il parametro per il nuovo thread.

Quindi, senza un esempio di come intendete iniziare questo nuovo thread, non posso dare una risposta definitiva. In generale, però, dovresti stare bene.

Anche la risposta dell’anima è corretta, è un po ‘più profonda di quanto dovrebbe essere:

Viene mantenuto, poiché il riferimento passato viene assegnato a una variabile forte, la variabile parametro. Questo e solo questo è il motivo della coppia di mantenimento / rilascio. (Impostare il parametro var su __weak e cosa succede?)

Si potrebbe ottimizzare via? Sarebbe come ottimizzare ogni coppia di mantenimento / rilascio su variabili locali, perché i parametri sono variabili locali. Questo può essere fatto, se il compilatore comprende il codice del foro all’interno del metodo, inclusi tutti i messaggi inviati e le chiamate di funzioni. Questo può essere applicato che raramente quel clang anche non prova a farlo. (Immagina che l’arg punta a una persona (solo) appartenente a un gruppo e il gruppo è dealloc’d: anche la persona sarebbe dealloc.)

E sì, non conservare argomenti in MRC era una specie di pericoloso, ma in genere gli sviluppatori conoscono il loro codice così bene, che hanno ottimizzato il mantenimento / rilascio senza pensarci.

Non aumenterà dietro le quinte. Sotto ARC se l’object è Strong rimarrà semplicemente in vita fino a quando non ci saranno più puntatori forti ad esso. Ma questo in realtà non ha nulla a che fare con l’object passato come parametro o meno.