ARC e cast colmato


166

Con ARC, non riesco più a lanciare CGColorRefa id. Ho imparato che devo fare un cast col ponte. Secondo clang docs :

Un cast con bridge è un cast in stile C annotato con una delle tre parole chiave:

(__bridge T) oplancia l'operando sul tipo di destinazione T. Se T è un tipo di puntatore oggetto conservabile, opdeve avere un tipo di puntatore non conservabile. Se Tè un tipo di puntatore non conservabile, op deve avere un tipo di puntatore oggetto conservabile. Altrimenti il ​​cast è mal formato. Non vi è alcun trasferimento di proprietà e ARC non inserisce operazioni di conservazione.

(__bridge_retained T) oplancia l'operando, che deve avere un tipo di puntatore oggetto conservabile, sul tipo di destinazione, che deve essere un tipo di puntatore non conservabile. ARC mantiene il valore, fatte salve le consuete ottimizzazioni sui valori locali, e il destinatario è responsabile del bilanciamento di +1.

(__bridge_transfer T) oplancia l'operando, che deve avere un tipo di puntatore non conservabile, sul tipo di destinazione, che deve essere un tipo di puntatore oggetto conservabile. ARC rilascerà il valore alla fine dell'espressione completa inclusa, fatte salve le consuete ottimizzazioni sui valori locali.

Questi cast sono necessari per trasferire oggetti dentro e fuori il controllo ARC; vedere la logica nella sezione sulla conversione dei puntatori di oggetti conservabili.

L'uso di a __bridge_retainedo __bridge_transfercast esclusivamente per convincere ARC a emettere un mantenimento o un rilascio sbilanciato, rispettivamente, è una forma scadente.

In che tipo di situazioni dovrei usare ciascuna?

Ad esempio, CAGradientLayerha una colorsproprietà che accetta una matrice di CGColorRefs. La mia ipotesi è che dovrei usare __brigequi, ma esattamente perché dovrei (o non dovrei) non è chiaro.


17
Hai già visto la sessione 323 del WWDC 2011? Questo spiega ARC molto meglio di quanto potessi qui. Copre tutti i dettagli dall'inizio alla fine. È una sessione da vedere per ogni sviluppatore Mac / iOS.
Rbrown

Anche questo potrebbe aiutare: stackoverflow.com/questions/14352494/…
Ewan Mellor

Link alla sessione del WWDC, non è stato banale da trovare: developer.apple.com/videos/play/wwdc2011/323 - Il bit rilevante è alle 23:15
Daniel

Risposte:


215

Sono d'accordo che la descrizione sia confusa. Da quando li ho appena afferrati, proverò a riassumere:

  • (__bridge_transfer <NSType>) opo in alternativa CFBridgingRelease(op)viene utilizzato per consumare un conteggio di mantenimento di un CFTypeReftempo trasferendolo su ARC. Questo potrebbe anche essere rappresentato daid someObj = (__bridge <NSType>) op; CFRelease(op);

  • (__bridge_retained <CFType>) opo in alternativa CFBridgingRetain(op)viene usato per consegnare una NSObjectterra CF mentre gli dà un conteggio di mantenimento di +1. Dovresti gestire un oggetto CFTypeRefcreato in questo modo come faresti con un risultato CFStringCreateCopy(). Questo potrebbe anche essere rappresentato daCFRetain((__bridge CFType)op); CFTypeRef someTypeRef = (__bridge CFType)op;

  • __bridgegira solo tra pointer-land e Objective-C object-land. Se non hai alcuna inclinazione a utilizzare le conversioni di cui sopra, usa questa.

Forse questo è utile. Io stesso, preferisco CFBridging…un po ' le macro piuttosto che i semplici calchi.


Il conteggio degli oggetti viene aumentato di 1 di arco quando si usa __bridge_transfer? Altrimenti sembrerebbe che nel momento in cui CFRelease () viene chiamato l'oggetto è sparito e non punta a nulla. Allo stesso modo, quando si utilizza __bridge_retain, ARC riduce il conteggio di mantenimento dell'operazione di 1? Altrimenti sembra che l'oggetto non sarebbe mai stato rilasciato correttamente.
Tony,

2
Una volta nella terra ARC non pensi più ai conteggi, ma solo ai riferimenti forti e deboli.
monkeydom,

4
Sì, se ti trovi in ​​una terra d'arco forte / debole sarebbe sufficiente, tuttavia quando stai transitando oggetti tra ambienti ad arco e non ad arco, devi ancora pensare alle implicazioni del conteggio di mantenimento sotto il cofano
Tony

3
Non proprio. Devi pensare solo di entrare e uscire dalla terra ARC. E questo è abbastanza evidente per afferrare il rilascio automatico. (abbastanza interessante: ARC risolve un modello comune come estrarre un oggetto da un dizionario e quindi rimuoverlo prima di usarlo, ecc.)
monkeydom

3
l'uso dello strumento Analizzatore (maiusc + comando + B) può aiutare a risolvere questo tipo di dubbi, poiché ti dirà in un linguaggio naturale se il codice corrente perde memoria. In tal caso, probabilmente stai usando un cast di mantenimento mentre dovresti usare un cast di non mantenimento. se l'analizzatore non ti avverte di nulla in quelle righe di codice, probabilmente stai andando bene con il codice attuale
Fabio Napodano,

55

Ho trovato un'altra spiegazione nella documentazione di iOS che penso sia più facile da capire:

  • __bridge trasferisce un puntatore tra Objective-C e Core Foundation senza trasferimento di proprietà.

  • __bridge_retained (CFBridgingRetain)lancia un puntatore Objective-C su un puntatore Core Foundation e trasferisce anche la proprietà all'utente.

    Sei responsabile di chiamare CFRelease o una funzione correlata per rinunciare alla proprietà dell'oggetto.

  • __bridge_transfer (CFBridgingRelease)sposta un puntatore non Objective-C su Objective-C e trasferisce anche la proprietà ad ARC.

    ARC è responsabile della rinuncia alla proprietà dell'oggetto.

Fonte: tipi di bridge gratuiti


33

Come seguito, in questo caso specifico, se utilizzi iOS, Apple consiglia di utilizzare UIColor e il suo -CGColormetodo per restituire CGColorRef in colorsNSArray. Nelle Transitioning to ARC Release Notes , nella sezione "Il compilatore gestisce oggetti CF restituiti da metodi Cocoa", è indicato che l'utilizzo di un metodo come quello -CGColorche restituisce un oggetto Core Foundation verrà gestito automaticamente dal compilatore.

Pertanto, suggeriscono di utilizzare un codice come il seguente:

CAGradientLayer *gradientLayer = (CAGradientLayer *)[self layer];
gradientLayer.colors = [NSArray arrayWithObjects:(id)[[UIColor darkGrayColor] CGColor],
                                                 (id)[[UIColor lightGrayColor] CGColor], nil];

Nota che al momento, al codice di esempio di Apple manca il cast (id) che ho sopra, che è ancora necessario per evitare un errore del compilatore.


Di solito puoi cavartela semplicemente lanciando il primo oggetto su (id) anziché su tutti, se preferisci.
Philippe Sabourin,

1
Questa domanda fa domande sul casting con ARC, dove il codice che hai incollato non è legale.
Joey Hagedorn,

11
@JoeyHagedorn - Forse hai perso il mio riferimento alla documentazione ARC nella prima frase della mia risposta, ma non solo è valido sotto ARC, ma è l'approccio raccomandato per fornire riferimenti CGColorRef in NSArrays da questi metodi di conversione UIColor. Io e molti altri, utilizzo questo codice esatto nelle applicazioni abilitate per ARC. Il casting immediato su (id) da un metodo che restituisce un oggetto Core Foundation collega automaticamente quell'oggetto ad ARC correttamente.
Brad Larson
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.