Apakah saya menyetel properti ke nol di dealloc saat menggunakan ARC?

125

Saya mencoba mempelajari Penghitungan Referensi Otomatis di iOS 5. Sekarang bagian pertama dari pertanyaan ini seharusnya mudah:

  1. Apakah benar bahwa saya TIDAK perlu menulis pernyataan properti rilis eksplisit di dealloc saya saat menggunakan ARC? Dengan kata lain, apakah benar bahwa berikut TIDAK memerlukan dealloc eksplisit?

    @interface MyClass : NSObject
    @property (strong, nonatomic) NSObject* myProperty;
    @end
    
    @implementation MyClass
    @synthesize myProperty;
    @end
  2. Pertanyaan saya berikutnya dan yang lebih penting datang dari sebuah baris di dokumen Transitioning to ARC Release Notes :

    Anda tidak harus (memang tidak bisa) melepaskan variabel instan, tetapi Anda mungkin perlu memanggil [self setDelegate: nil] pada kelas sistem dan kode lain yang tidak dikompilasi menggunakan ARC.

    Ini menimbulkan pertanyaan: bagaimana saya tahu kelas sistem mana yang tidak dikompilasi dengan ARC? Kapan saya harus membuat dealloc saya sendiri dan secara eksplisit menetapkan properti yang sangat mempertahankan ke nol? Haruskah saya menganggap semua kelas kerangka kerja NS dan UI yang digunakan dalam properti memerlukan deallocs eksplisit?

Ada banyak informasi tentang SO dan di tempat lain tentang praktik melepaskan ivar dukungan properti ketika menggunakan pelacakan referensi manual, tetapi relatif sedikit tentang hal ini ketika menggunakan ARC.

emfurry
sumber

Jawaban:

197

Jawaban singkat : tidak, Anda tidak perlu mencari properti di deallocbawah ARC.

Jawaban panjang : Anda seharusnya tidak pernah menghilangkan properti dealloc, bahkan dalam manajemen memori manual.

Di MRR, Anda harus melepaskan ivar Anda . Properti nilling out berarti memanggil setter, yang dapat meminta kode yang tidak boleh disentuh dealloc(misalnya jika kelas Anda, atau subkelas, menimpa setter). Demikian pula itu dapat memicu notifikasi KVO. Melepaskan ivar sebagai gantinya menghindari perilaku yang tidak diinginkan ini.

Di ARC, sistem secara otomatis melepaskan setiap ivar untuk Anda, jadi jika hanya itu yang Anda lakukan, Anda bahkan tidak perlu mengimplementasikannya dealloc. Namun, jika Anda memiliki ivars non-objek yang memerlukan penanganan khusus (mis. Buffer yang Anda perlukan free()), Anda masih harus berurusan dengan yang didealloc .

Selain itu, jika Anda menetapkan diri sebagai delegasi objek apa pun, Anda harus membatalkan setel hubungan itu dealloc(ini adalah sedikit tentang menelepon [obj setDelegate:nil]). Catatan tentang melakukan ini di kelas yang tidak dikompilasi dengan ARC adalah anggukan terhadap sifat lemah. Jika kelas secara eksplisit menandai delegatepropertinya weakmaka Anda tidak perlu melakukan ini, karena sifat properti yang lemah berarti akan ditagih untuk Anda. Namun jika properti ditandai assignmaka Anda harus nil itu keluar di Anda dealloc, jika tidak kelas dibiarkan dengan pointer menggantung dan kemungkinan akan crash jika mencoba mengirim pesan kepada delegasinya. Perhatikan bahwa ini hanya berlaku untuk hubungan yang tidak dipertahankan, seperti delegasi.

Lily Ballard
sumber
2
Ini masuk akal! Izinkan saya bertanya kepada Anda: skenario umum yang saya miliki adalah bahwa saya memiliki MyController : UIViewControllerkelas yang membuat dan memiliki UIView dan juga menetapkan delegasi tampilan untuk dirinya sendiri. Ini adalah pemilik penahan tunggal dari pandangan itu. Ketika pengontrol mendapatkan dealloc'ed, maka view juga harus mendapatkan dealloc'ed. Apakah itu penting jika pointer delegasi menggantung?
emfurry
4
@ emfurry: Mungkin tidak, karena saat pengontrol tampilan Anda mati, tampilan itu sendiri seharusnya tidak berada dalam hierarki tampilan dan tidak boleh melakukan apa pun, tetapi sebaiknya jangan membuat asumsi. Bagaimana jika tampilan dijadwalkan bekerja secara tidak sinkron untuk dilakukan kemudian, dan tampilan itu sendiri berakhir lebih lama dari pengontrol tampilan dengan waktu yang singkat (misalnya karena pekerjaan asinkron mempertahankan tampilan sementara)? Yang terbaik adalah hanya mengeluarkan delegasi agar aman. Dan pada kenyataannya, jika tampilan yang dimaksud adalah UIWebView, dokumen secara eksplisit menyatakan bahwa Anda perlu meniadakan delegasi.
Lily Ballard
3
@zeiteisen: Tidak. unsafe_unretainedPersis sama dengan assignproperti dan merupakan perilaku normal untuk mendelegasikan hubungan di bawah MRR, dan ini harus dituntaskan.
Lily Ballard
4
Saya tidak setuju dengan pernyataan tentang tidak menggunakan setter di dealloc dengan MRC. Apple tidak merekomendasikannya tetapi mereka melakukannya dalam kode mereka juga. Anda sebenarnya dapat membuat masalah baru dengan tidak menggunakan setter. Ada beberapa diskusi besar tentang itu. Apa yang penting adalah menulis setter dengan benar (itu harus berperilaku dengan benar jika Anda memberikan nilai nol) dan terkadang memperhatikan urutan deallokasi.
Sulthan
7
@Sulthan: Apakah menggunakan setter di dealloc atau tidak adalah sekaleng cacing, tetapi posisi saya pada dasarnya bermuara pada: Anda ingin memanggil kode sesedikit mungkin dalam dealloc. Setter memiliki kecenderungan untuk memasukkan efek samping, baik dengan mengesampingkan dalam subkelas, atau melalui KVO, atau mekanisme lainnya. Efek samping dalam dealloc terutama harus dihindari seperti wabah. Jika Anda dapat menghapus panggilan metode dari dealloc, Anda harus melakukannya. Ini disederhanakan ke: jangan panggil setter di dealloc.
Lily Ballard
2

Hanya untuk memberikan jawaban yang berlawanan ...

Jawaban singkat : tidak, Anda tidak perlu menghilangkan properti yang disintesis secara otomatis di deallocbawah ARC. Dan Anda tidak harus menggunakan setter untuk mereka yang masukinit .

Jawaban panjang : Anda harus menemukan properti yang disintesis khusus di dealloc, bahkan di bawah ARC. Dan Anda harus menggunakan setter bagi mereka di init.

Intinya properti Anda yang disintesis khusus harus aman dan simetris tentang pembatalan.

Penyetel kemungkinan untuk penghitung waktu:

-(void)setTimer:(NSTimer *)timer
{
    if (timer == _timer)
        return;

    [timer retain];
    [_timer invalidate];
    [_timer release];
    _timer = timer;
    [_timer fire];
}

Penyetel yang mungkin untuk scrollview, tableview, webview, textfield, ...:

-(void)setScrollView:(UIScrollView *)scrollView
{
    if (scrollView == _scrollView)
        return;

    [scrollView retain];
    [_scrollView setDelegate:nil];
    [_scrollView release];
    _scrollView = scrollView;
    [_scrollView setDelegate:self];
}

Penyetel yang mungkin untuk properti KVO:

-(void)setButton:(UIButton *)button
{
    if (button == _button)
        return;

    [button retain];
    [_button removeObserver:self forKeyPath:@"tintColor"];
    [_button release];
    _button = button;
    [_button addObserver:self forKeyPath:@"tintColor" options:(NSKeyValueObservingOptions)0 context:NULL];
}

Maka Anda tidak perlu menduplikasi kode apapun untuk dealloc, didReceiveMemoryWarning, viewDidUnload, ... dan properti Anda aman dapat dibuat publik. Jika Anda khawatir tentang nil out properti di dealloc, maka mungkin sudah saatnya Anda memeriksa lagi setter Anda.

Cur
sumber