Kapan menggunakan -retainCount?

110

Saya ingin tahu dalam situasi apa yang Anda gunakan -retainCountsejauh ini, dan pada akhirnya masalah yang dapat terjadi saat menggunakannya.

Terima kasih.

Moszi
sumber
5
Anda tidak boleh menggunakan -retainCount.
holex
3
(Kecuali jika Anda harus melakukannya. Terkadang sangat berguna untuk membantu memahami apa yang sedang terjadi, selama Anda menghargai bahwa hal itu terkadang dapat menyesatkan. Dan, tentu saja, tidak diizinkan sama sekali jika menggunakan ARC.)
Hot Licks

Jawaban:

243

Anda tidak boleh menggunakan -retainCount, karena tidak pernah memberi tahu Anda sesuatu yang berguna. Implementasi kerangka kerja Foundation dan AppKit / UIKit tidak jelas; Anda tidak tahu apa yang dipertahankan, mengapa itu dipertahankan, siapa yang mempertahankannya, kapan itu dipertahankan, dan seterusnya.

Sebagai contoh:

  • Anda akan berpikir itu [NSNumber numberWithInt:1]akan memiliki retainCount1. Tidak. Ini 2.
  • Anda akan berpikir itu @"Foo"akan memiliki retainCount1. Tidak. Ini 1152921504606846975.
  • Anda akan berpikir itu [NSString stringWithString:@"Foo"]akan memiliki retainCount1. Tidak. Sekali lagi, ini 1152921504606846975.

Pada dasarnya, karena apa pun dapat mempertahankan objek (dan karenanya mengubahnya retainCount), dan karena Anda tidak memiliki sumber untuk sebagian besar kode yang menjalankan aplikasi, objek menjadi retainCounttidak berarti.

Jika Anda mencoba melacak mengapa sebuah objek tidak dibatalkan alokasinya, gunakan alat Kebocoran di Instrumen. Jika Anda mencoba melacak mengapa suatu objek dibatalkan alokasinya terlalu cepat, gunakan alat Zombies di Instrumen.

Tapi jangan gunakan -retainCount. Itu adalah metode yang benar-benar tidak berguna.

edit

Harap semua orang membuka http://bugreport.apple.com dan meminta agar -retainCounttidak digunakan lagi. Semakin banyak orang yang memintanya, semakin baik.

edit # 2

Sebagai pemutakhiran, [NSNumber numberWithInt:1]sekarang memiliki retainCount9223372036854775807. Jika kode Anda mengharapkannya menjadi 2, kode Anda sekarang telah rusak.

Dave DeLong
sumber
4
Terima kasih @ Dave-Delong atas contoh Anda.
Moszi
1
RetretCount saat ini berguna untuk lajang. (Sekarang pertanyaannya adalah seberapa berguna lajang ...) - (NSUInteger)retainCount{return NSUIntegerMax;}.
Joe
8
@Joe Anda bisa membuat tunggal tanpa menimpa retainCount.
Dave DeLong
5
@ Joe, saya sadar akan hal itu; Google "obyektif-c tunggal" untuk semua diskusi tentang mengapa contoh itu tidak terlalu bagus.
Dave DeLong
2
Satu hal yang saya gunakan - @ DaveDeLong, Anda mungkin menemukan ini salah juga, tapi menurut saya tidak - adalah menimpa deallocs dan init dan meletakkan NSLog di dalamnya (bahkan dengan ARC). Ini memberi saya ide bagus tentang apakah objek akan dibatalkan alokasinya atau tidak, yang merupakan pertanyaan sebenarnya yang biasanya kami coba jawab ..
Dan Rosenstark
50

TIDAK PERNAH!

Sungguh. Jangan lakukan itu.

Cukup ikuti Panduan Manajemen Memori dan hanya sebarkan apa yang Anda alloc, newatau copy(atau apa pun yang Anda minta retainpada awalnya).

@bbum mengatakan yang terbaik di sini di SO , dan bahkan lebih detail di blognya .

Abizern
sumber
8
Karena Anda akan mengira Anda sedang menghitung memori, tetapi Anda salah melakukannya.
Abizern
@Abizern - dan bagaimana dengan situasi lajang di salah satu jawaban lain?
Moszi
3
Untuk menambah ini, informasi apa pun yang dapat Anda peroleh dari -retainCountdapat diperoleh (dengan lebih detail) dari Instrumen dan alatnya.
Dave DeLong
3
Untuk menambah apa yang dikatakan Dave; jumlah retensi absolut suatu objek adalah detail implementasi. Baik detail internal objek dan / atau detail objek lain yang mungkin telah dilewati objek. Memanggil retain, retain, retain, autorelease, autorelease, autoreleasebisa menjadi hasil yang valid sempurna lewat sebuah objek melalui UIKit API, misalnya.
bbum
2
@ d11wtq Jika mempertahankanCount pernah == 0, singularitas telah tercapai!
bbum
14

Objek autoreleased adalah salah satu kasus di mana pemeriksaan -retainCount tidak informatif dan berpotensi menyesatkan. Jumlah retensi tidak memberi tahu Anda tentang berapa kali -autorelease dipanggil pada suatu objek dan oleh karena itu berapa kali akan dirilis ketika kumpulan autorelease saat ini habis.

Yunus
sumber
1
Terima kasih - ini poin yang bagus. Ini adalah jawaban pertama yang sebenarnya memiliki alasan yang dijelaskan mengapa tidak menggunakan retretcount, selain yang umum "jangan".
Moszi
1
@Moszi: Pertanyaan Anda adalah "Kapan menggunakan retretCount?" - jika Anda tidak bermaksud menanyakan pertanyaan itu, Anda seharusnya menanyakan hal lain.
Chuck
@chuck - sebenarnya saya tertarik dengan "kapan harus menggunakannya", namun tampaknya setiap jawaban akan menjadi "tidak pernah" ... Tapi - saya rasa Anda benar. Saya akan membiarkan pertanyaan terbuka selama beberapa hari, dan jika tidak akan ada jawaban selain tidak pernah, maka saya akan menerima "tidak pernah" sebagai jawaban.
Moszi
10

Saya tidak menemukan retainCounts sangat berguna ketika diperiksa menggunakan 'Instrumen'.

Dengan menggunakan alat 'alokasi', pastikan 'Rekam jumlah referensi' diaktifkan dan Anda dapat masuk ke objek apa pun dan melihat riwayat terus menghitungnya.

Dengan memasangkan allocs dan rilis, Anda bisa mendapatkan gambaran yang baik tentang apa yang sedang terjadi dan sering kali menyelesaikan kasus-kasus sulit di mana sesuatu tidak dirilis.

Ini tidak pernah mengecewakan saya - termasuk menemukan bug di rilis beta awal iOS.

Agil
sumber
5

Lihatlah dokumentasi Apple di NSObject, itu cukup banyak mencakup pertanyaan Anda: NSObject mempertahankanCount

Singkatnya, retretCount mungkin tidak berguna bagi Anda kecuali Anda telah menerapkan sistem penghitungan referensi Anda sendiri (dan saya hampir dapat menjamin Anda tidak akan melakukannya).

Dalam kata-kata Apple sendiri, retensiCount "biasanya tidak ada nilainya dalam men-debug masalah manajemen memori".

lxt
sumber
Pertama-tama terima kasih atas jawabannya. Biasanya reaksi orang terhadap pertanyaan ini adalah "TIDAK PERNAH". (Lihat jawabannya). Sebenarnya "tidak ada nilai dalam debugging" tidak berarti "TIDAK PERNAH". Jadi pertanyaan saya adalah - mengapa perasaan kuat untuk tidak menggunakannya (misalnya dalam implementasi tunggal - salah satu jawabannya lagi)?
Moszi
Saya kira Anda perlu memberikan lebih banyak informasi tentang untuk apa Anda menggunakannya. Penggunaan yang dapat diterima adalah, seperti yang disarankan oleh Apple, mengesampingkan retretCount untuk menerapkan sistem penghitungan referensi Anda sendiri. Tetapi dalam praktiknya, Anda tidak akan pernah melihatnya (saya tidak pernah melihatnya). Reaksi yang kuat umumnya berasal dari fakta bahwa Apple sendiri telah menganjurkan (di grup email mereka, dokumen, forum pengembang, dll) untuk tidak menggunakan retensiCount.
lxt
1
@Moszi: Debugging adalah satu-satunya situasi di mana kebanyakan orang dapat menganggapnya memiliki nilai, jadi jika tidak dapat diandalkan di sana, itu tidak akan pernah berguna. Apa kegunaan lain yang Anda pikirkan?
Chuck
4

Tentu saja Anda tidak boleh menggunakan metode retensiCount dalam kode Anda, karena arti nilainya bergantung pada berapa banyak autorelease yang telah diterapkan ke objek dan itu adalah sesuatu yang tidak dapat Anda prediksi. Namun ini sangat berguna untuk debugging - terutama saat Anda mencari kebocoran memori dalam kode yang memanggil metode objek Appkit di luar loop event utama - dan ini tidak boleh dihentikan.

Dalam upaya Anda untuk menyampaikan maksud Anda, Anda secara serius melebih-lebihkan sifat nilai yang tidak dapat dipahami. Memang benar bahwa ini tidak selalu merupakan hitungan referensi. Ada beberapa nilai khusus yang digunakan untuk flag, misalnya untuk menunjukkan bahwa objek tidak boleh dibatalkan alokasinya. Angka seperti 1152921504606846975 terlihat sangat misterius sampai Anda menuliskannya dalam hex dan mendapatkan 0xfffffffffffffff. Dan 9223372036854775807 adalah 0x7fffffffffffffff dalam hex. Dan sebenarnya tidak terlalu mengherankan bahwa seseorang akan memilih untuk menggunakan nilai seperti ini sebagai flag, mengingat akan memakan waktu hampir 3000 tahun untuk mendapatkan retretCount setinggi angka yang lebih besar, dengan asumsi Anda menaikkan retretCount 100.000.000 kali per detik.

Marc Culler
sumber
3

Masalah apa yang bisa Anda dapatkan dari menggunakannya? Yang dilakukannya hanyalah mengembalikan jumlah retensi objek. Saya tidak pernah menyebutnya dan tidak dapat memikirkan alasan apa pun yang saya lakukan. Saya telah menimpanya dalam jumlah tunggal untuk memastikan alokasi tersebut tidak dibatalkan.

ughoavgfhw.dll
sumber
2
Tidak ada alasan untuk menimpanya dalam kasus tunggal. Tidak ada jalur kode di Foundation / CoreFoundation yang digunakan retainCountuntuk manajemen memori.
bbum
Tidakkah rilis menggunakannya untuk memutuskan apakah ia harus memanggil dealloc?
ughoavgfhw
2
Nggak; implementasi internal retret / release / autorelease memiliki akar yang dalam di CoreFoundation dan sama sekali tidak seperti yang Anda harapkan. Pergi ambil sumber CoreFoundation (tersedia) dan lihat.
bbum
3

Anda tidak perlu khawatir tentang kebocoran memori sampai aplikasi Anda aktif dan berjalan dan melakukan sesuatu yang berguna.

Setelah itu, jalankan Instrumen dan gunakan aplikasi dan lihat apakah kebocoran memori benar-benar terjadi. Dalam kebanyakan kasus, Anda membuat objek sendiri (sehingga Anda memilikinya) dan lupa melepaskannya setelah selesai.

Jangan mencoba dan mengoptimalkan kode Anda saat Anda menulisnya, tebakan Anda tentang apa yang mungkin membocorkan memori atau memakan waktu terlalu lama seringkali salah ketika Anda benar-benar menggunakan aplikasi secara normal.

Cobalah dan tulis kode yang benar, misalnya jika Anda membuat objek menggunakan alok dan semacamnya, maka pastikan Anda melepaskannya dengan benar.

ExitToShell
sumber
0

Anda tidak boleh menggunakannya dalam kode Anda, tetapi itu pasti bisa membantu saat debugging

iosdevnyc.dll
sumber
0

Jangan pernah menggunakan -retainCount dalam kode Anda. Namun jika Anda menggunakan, Anda tidak akan pernah melihatnya mengembalikan nol. Pikirkan mengapa. :-)

hrchen
sumber
0

Contoh yang digunakan dalam posting Dave adalah NSNumber dan NSStrings ... jadi, jika Anda menggunakan beberapa kelas lain, seperti UIViews, saya yakin Anda akan mendapatkan jawaban yang benar (Jumlah retensi tergantung pada implementasi, dan dapat diprediksi).

Peng
sumber