ARC dan pemain yang dijembatani

166

Dengan ARC, saya tidak bisa lagi dilemparkan CGColorRefke id. Saya belajar bahwa saya perlu melakukan pemeran penghubung. Menurut dentang dokumen :

Pemain yang dijembatani adalah pemain gaya-C yang diberi anotasi dengan salah satu dari tiga kata kunci:

(__bridge T) opmelemparkan operan ke tipe tujuan T. Jika T adalah tipe pointer objek yang dapat dipertahankan, maka opharus memiliki tipe pointer yang tidak dapat dipertahankan. Jika Tadalah tipe pointer yang tidak dapat dipertahankan, maka op harus memiliki tipe pointer objek yang dapat dipertahankan. Kalau gips tidak terbentuk dengan baik. Tidak ada transfer kepemilikan, dan ARC memasukkan tidak ada operasi penahanan.

(__bridge_retained T) opmelemparkan operan, yang harus memiliki jenis penunjuk objek yang dapat dipertahankan, ke jenis tujuan, yang harus merupakan jenis penunjuk yang tidak dapat dipertahankan. ARC mempertahankan nilainya, tunduk pada optimasi yang biasa dilakukan pada nilai-nilai lokal, dan penerima bertanggung jawab untuk menyeimbangkan +1 tersebut.

(__bridge_transfer T) opmelemparkan operan, yang harus memiliki jenis penunjuk yang tidak dapat dipertahankan, ke jenis tujuan, yang harus merupakan jenis penunjuk objek yang dapat dipertahankan. ARC akan merilis nilai pada akhir ekspresi penuh terlampir, tunduk pada optimasi biasa pada nilai-nilai lokal.

Gips ini diperlukan untuk mentransfer objek masuk dan keluar dari kontrol ARC; lihat alasan di bagian tentang konversi pointer objek yang dapat dipertahankan.

Menggunakan __bridge_retainedatau __bridge_transfermelemparkan murni untuk meyakinkan ARC untuk memancarkan masing-masing mempertahankan atau melepaskan tidak seimbang, adalah bentuk yang buruk.

Dalam situasi apa saya akan menggunakan masing-masing?

Misalnya, CAGradientLayermemiliki colorsproperti yang menerima array CGColorRefs. Dugaan saya adalah bahwa saya harus menggunakan di __brigesini, tetapi mengapa saya harus (atau tidak seharusnya) tidak jelas.

Tanpa Morrow
sumber
17
Sudahkah Anda menonton WWDC 2011 sesi 323? Itu menjelaskan ARC jauh lebih baik daripada yang saya bisa di sini. Ini mencakup semua detail dari awal hingga akhir. Sesi ini harus dilihat untuk setiap pengembang Mac / iOS.
rbrown
Ini mungkin membantu juga: stackoverflow.com/questions/14352494/…
Ewan Mellor
Tautan ke sesi WWDC, itu tidak mudah untuk menemukan: developer.apple.com/videos/play/wwdc2011/323 - Bit yang relevan ada di 23:15
Daniel

Jawaban:

215

Saya setuju bahwa uraiannya membingungkan. Karena saya baru saja memahami mereka, saya akan mencoba merangkum:

  • (__bridge_transfer <NSType>) opatau sebagai alternatif CFBridgingRelease(op)digunakan untuk mengkonsumsi retain-count CFTypeRefsementara mentransfernya ke ARC. Ini juga bisa diwakili olehid someObj = (__bridge <NSType>) op; CFRelease(op);

  • (__bridge_retained <CFType>) opatau sebagai alternatif CFBridgingRetain(op)digunakan untuk menyerahkan lahan NSObjectCF sambil memberikan penghitungan +1. Anda harus menangani CFTypeRefAnda membuat cara ini sama seperti Anda akan menangani hasilnya CFStringCreateCopy(). Ini juga bisa diwakili olehCFRetain((__bridge CFType)op); CFTypeRef someTypeRef = (__bridge CFType)op;

  • __bridgehanya melemparkan antara pointer-land dan Objective-C objek-land. Jika Anda tidak memiliki kecenderungan untuk menggunakan konversi di atas, gunakan yang ini.

Mungkin ini bermanfaat. Saya sendiri, saya lebih suka CFBridging…makro daripada gips.

monyet
sumber
Apakah objek mempertahankan jumlah bertambah dengan busur sebesar 1 saat Anda menggunakan __bridge_transfer? Kalau tidak, tampaknya saat CFRelease () disebut objek hilang dan tidak menunjukkan apa-apa. Demikian pula, ketika Anda menggunakan __bridge_retain, apakah ARC mengurangi jumlah retain op oleh 1? Jika tidak, objek itu tidak akan pernah dirilis dengan benar.
Tony
2
Setelah berada di ARC, Anda tidak lagi berpikir tentang mempertahankan jumlah, hanya tentang referensi yang kuat dan lemah.
monkeydom
4
Ya, jika Anda hanya di tanah busur yang kuat / lemah akan cukup, namun ketika Anda mentransisikan objek antara lingkungan busur dan non-busur Anda masih harus memikirkan implikasi jumlah penahan di bawah kap
Tony
3
Tidak juga. Anda harus berpikir tentang masuk dan keluar dari tanah ARC. Dan ini cukup menarik untuk memahami autoreleasing. (cukup menarik: ARC memperbaiki pola umum seperti mengeluarkan objek dari kamus dan kemudian menghapusnya sebelum menggunakannya, dll.)
monkeydom
3
menggunakan alat Analyzer (shift + command + B) dapat membantu dalam menyelesaikan keraguan semacam itu, karena itu akan memberi tahu Anda dalam bahasa alami jika kode saat ini bocor memori. Jika ya, Anda mungkin menggunakan penahan sementara Anda harus menggunakan penahan tidak. jika Analyzer tidak memperingatkan Anda tentang apa pun dalam baris kode itu, Anda mungkin melakukannya dengan baik dengan kode saat ini
Fabio Napodano
55

Saya menemukan penjelasan lain dalam dokumentasi iOS yang menurut saya lebih mudah dimengerti:

  • __bridge mentransfer pointer antara Objective-C dan Core Foundation tanpa transfer kepemilikan.

  • __bridge_retained (CFBridgingRetain)melemparkan pointer Objective-C ke pointer Yayasan Core dan juga mentransfer kepemilikan kepada Anda.

    Anda bertanggung jawab untuk memanggil CFRelease atau fungsi terkait untuk melepaskan kepemilikan objek.

  • __bridge_transfer (CFBridgingRelease)memindahkan pointer non-Objective-C ke Objective-C dan juga mentransfer kepemilikan ke ARC.

    ARC bertanggung jawab untuk melepaskan kepemilikan objek.

Sumber: Jenis Bridged Bebas Pulsa

gregschlom
sumber
33

Sebagai tindak lanjut, dalam kasus khusus ini, jika Anda menggunakan iOS, Apple merekomendasikan untuk menggunakan UIColor dan -CGColormetodenya untuk mengembalikan CGColorRef ke dalam colorsNSArray. Dalam Transitioning to ARC Release Notes , di bawah bagian "The Compiler Menangani Objek CF yang Dikembalikan Dari Metode Kakao", diindikasikan bahwa menggunakan metode seperti -CGColoryang mengembalikan objek Core Foundation akan secara otomatis ditangani dengan baik oleh kompiler.

Dengan demikian, mereka menyarankan menggunakan kode seperti berikut:

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

Perhatikan bahwa pada saat ini, kode contoh Apple tidak memiliki tanda (id) yang saya miliki di atas, yang masih perlu untuk menghindari kesalahan kompiler.

Brad Larson
sumber
Anda biasanya dapat pergi hanya dengan melemparkan objek pertama ke (id) alih-alih semuanya, jika Anda mau.
Philippe Sabourin
1
Pertanyaan ini menanyakan tentang casting dengan ARC, di mana kode yang Anda tempel tidak sah.
Joey Hagedorn
11
@ JoeyHagedorn - Mungkin Anda melewatkan referensi saya ke dokumentasi ARC pada kalimat pertama dari jawaban saya, tetapi tidak hanya valid di bawah ARC, ini adalah pendekatan yang disarankan untuk menyediakan referensi CGColorRef ke dalam NSArrays dari metode konverter UIColor ini. Saya, dan banyak lainnya, menggunakan kode ini dalam aplikasi yang mendukung ARC. Pengecoran langsung ke (id) dari metode yang mengembalikan objek Core Foundation secara otomatis menjembatani objek itu ke ARC dengan benar.
Brad Larson