KVO dan ARC cara menghapusObserver

87

Bagaimana Anda menghapus pengamat dari objek di bawah ARC ? Apakah kita hanya menambahkan pengamat dan lupa menghapusnya? Jika kita tidak lagi mengelola memori secara manual di mana kita berhenti mengamati?

Misalnya, pada pengontrol tampilan:

[self.view addObserver:self
            forKeyPath:@"self.frame"
               options:NSKeyValueObservingOptionNew 
               context:nil];

Sebelumnya, saya akan memanggil metode removeObserver:pengontrol tampilan dealloc.

mabuk
sumber
4
Perhatikan bahwa KVO .frame merupakan ide yang sangat buruk. Seperti yang ditulis di bagian lain oleh teknisi Apple di StackOverflow, properti bingkai UIKit tidak sesuai dengan KVO. Jika berhasil, itu hanya kebetulan belaka.
steipete
2
Tidak harus keyPath Anda menjadi @"frame"bukan @"self.frame"?
Besi

Jawaban:

126

Anda masih dapat menerapkan di -deallocbawah ARC, yang tampaknya merupakan tempat yang tepat untuk menghapus pengamatan nilai kunci. Anda hanya tidak menelepon[super dealloc] dari dalam metode ini lagi.

Jika Anda menimpa -releasesebelumnya, Anda melakukan sesuatu dengan cara yang salah.

Brad Larson
sumber
1
Apa kau yakin tentang ini? Saya mengutip dari clang.llvm.org/docs/… , bagian 7.1.2. dealloc: "Rasional: meskipun ARC menghancurkan variabel instance secara otomatis, masih ada alasan yang sah untuk menulis metode dealloc, seperti membebaskan sumber daya yang tidak dapat dipertahankan. Gagal memanggil [super dealloc] dengan metode seperti itu hampir selalu merupakan bug."
Elise van Looij
@ElisevanLooij Ya itu benar. Jika Anda berasal dari kelas ini, tampaknya jelas bahwa Anda harus menelepon [super dealloc]. Siapa lagi yang harus melakukan ini untuk Anda.
Björn Landmesser
@ElisevanLooij Ups, mestinya sudah diperiksa sebelumnya. Tidak diperbolehkan untuk memanggil [super dealloc]dengan metode dealloc. Tidak tahu bagaimana ini akan bekerja saat membuat subclass kelas yang disebutkan. Mungkin hanya disarankan untuk menggunakan finalizesebagai gantinya (jika Anda menelepon [super finalize])
Björn Landmesser
17
@ElisevanLooij - Hal yang mereka coba sampaikan adalah berkaitan dengan kasus manajemen memori manual. Karena tidak memanggil yang [super dealloc]terakhir dalam metode itu selalu merupakan bug di bawah manajemen memori manual, kompilator menanganinya untuk Anda sekarang, itulah sebabnya Anda tidak dapat memanggil -deallocsecara langsung lagi. Satu-satunya hal yang Anda masukkan ke dalam -deallocmetode di bawah ARC adalah sumber daya non-objek apa pun yang perlu Anda bebaskan, atau tugas pembersihan seperti menghapus pengamat. Kata-kata yang mereka gunakan agak berlumpur, tapi inilah yang mereka maksud.
Brad Larson
7
@ BjörnMilcke - Saat saya mengomentari jawaban Elise, -finalizedigunakan untuk ini di bawah pengumpulan sampah, di mana -dealloctidak pernah dipanggil, tetapi sangat dapat diterima untuk menempatkan kode ini di -deallocbawah ARC. [super dealloc]dipanggil untuk Anda secara otomatis, itulah sebabnya mengapa salah memanggilnya di bawah ARC.
Brad Larson
1

Saya melakukannya dengan kode ini

- (void)dealloc
{
@try{
    [self.uAvatarImage removeObserver:self forKeyPath:@"image" context:nil];
} @catch(id anException) {
    //do nothing, obviously it wasn't attached because an exception was thrown
}
}    
pengguna3461902
sumber
2
Apa gunanya penanganan Exception dealloc? Sudah terlambat untuk melakukan sesuatu tentang itu.
Abizern
Apa gunanya menghapus pengamat pada variabel instan di dealloc? UAvatarImage ini akan segera dibatalkan alokasinya bersama dengan pengamat mana pun yang telah berlangganan jalur utamanya.
shoumikhin
1
@shoumikhin Saya menggunakan ARC dan saya harus menghapus pengamat dalam metode dealloc. Saya memiliki pertanyaan yang sama dengan Anda. Namun, ketika saya menjalankan beberapa contoh kelas akhirnya saya mendapat kesalahan exc_bad_address. Melakukan ini menyelesaikan masalah. Juga, jawaban dari sini stackoverflow.com/questions/32490808/… membantu saya menemukan masalah tersebut.
mac10688
-2

Di tempat lain di stack overflow, Chris Hanson menyarankan penggunaan metode finalisasi untuk tujuan ini dan menerapkan metode pembatalan terpisah sehingga pemilik dapat memberi tahu objek bahwa mereka sudah selesai. Di masa lalu saya telah menemukan solusi Hanson untuk dipikirkan dengan baik, jadi saya akan pergi dengan itu.

Elise van Looij
sumber
13
Perhatikan bahwa yang dia maksud adalah pengumpulan sampah di sana, bukan ARC (jawabannya ditulis tahun 2008). Di bawah pengumpulan sampah, -dealloctidak pernah dipanggil. Di ARC, itu benar. Sangat dapat diterima untuk menghapus pengamat KVO -dealloc, seperti yang ditunjukkan oleh Chris Lattner (yang tahu apa yang dia bicarakan) di forum pengembang Apple di sini: devforums.apple.com/message/475850
Brad Larson
3
Terima kasih Brad, telah melakukan semua pekerjaan ini. Tidak untuk menyelesaikan, ya untuk dealloc tetapi tanpa [super dealloc]. Sederhana sekali, begitu Anda mengetahuinya. Hei, @drunknbass, terima jawaban pria itu!
Elise van Looij