ARC'yi kullanırken dealloc'ta özellikleri nil olarak ayarlamalı mıyım?


125

İOS 5'te Otomatik Referans Saymayı öğrenmeye çalışıyorum. Şimdi bu sorunun ilk kısmı kolay olmalı:

  1. Ben emin düzeltmek mi DEĞİL ARC kullanırken benim dealloc açık bırakma-mülk ifadeleri yazmaya gerek? Başka bir deyişle, şu mu doğrudur DEĞİL bir açık dealloc gerek?

    @interface MyClass : NSObject
    @property (strong, nonatomic) NSObject* myProperty;
    @end
    
    @implementation MyClass
    @synthesize myProperty;
    @end
  2. Bir sonraki ve daha önemli sorum , ARC Sürüm Notlarına Geçiş belgesindeki bir satırdan geliyor :

    Örnek değişkenleri serbest bırakmanız gerekmez (aslında yapamazsınız), ancak sistem sınıflarında ve ARC kullanılarak derlenmeyen diğer kodlarda [self setDelegate: nil] 'i çağırmanız gerekebilir.

    Bu şu soruyu akla getiriyor: Hangi sistem sınıflarının ARC ile derlenmediğini nasıl bilebilirim? Kendi dealloc'umu ne zaman oluşturmalıyım ve açıkça güçlü tutma özelliklerini nil olarak ayarlamalıyım? Özelliklerde kullanılan tüm NS ve UI çerçeve sınıflarının açık dealloc gerektirdiğini varsaymalı mıyım?

Manüel referans izlemeyi kullanırken bir mülkün destek ivarını serbest bırakma uygulamaları hakkında SO ve başka yerlerde bol miktarda bilgi vardır, ancak ARC kullanırken bu konuda nispeten az şey vardır.

Yanıtlar:


197

Kısa cevap : hayır, deallocARC altındaki özellikleri sıfırlamanız gerekmez .

Uzun cevap : deallocManuel bellek yönetiminde bile, içindeki özellikleri asla sıfırlamamalısınız .

MRR'de ivarlarınızı serbest bırakmalısınız . Özelliklerin sıfırlanması, girmemesi gereken kodu çağırabilen ayarlayıcıları çağırmak anlamına gelir dealloc(örneğin, sınıfınız veya bir alt sınıf, ayarlayıcıyı geçersiz kılarsa). Benzer şekilde KVO bildirimlerini tetikleyebilir. Bunun yerine ivarın serbest bırakılması, bu istenmeyen davranışları önler.

ARC'de, sistem tüm ivarları sizin için otomatik olarak serbest bırakır, böylece tüm yaptığınız buysa, uygulamak zorunda bile değilsiniz dealloc. Ancak, özel işlem gerektiren herhangi bir nesne olmayan ivarınız varsa (örneğin, ihtiyacınız olan tahsis edilmiş tamponlar free()), yine de içindekilerle uğraşmanız gerekir dealloc.

Dahası, kendinizi herhangi bir nesnenin temsilcisi olarak belirlediyseniz, bu ilişkinin ayarını kaldırmalısınız dealloc(bu, arama ile ilgili kısımdır [obj setDelegate:nil]). ARC ile derlenmemiş sınıflarda bunu yapmakla ilgili not, zayıf özelliklere bir selamdır. Eğer sınıf, kendi delegateözelliğini açıkça işaretlerse, weakbunu yapmanız gerekmez, çünkü zayıf özelliklerin doğası sizin için sıfırlanacağı anlamına gelir. Bununla birlikte, eğer özellik işaretlenmişse, assigno zaman onu sıfırlamalısınız dealloc, aksi takdirde sınıf sarkan bir işaretçi ile bırakılır ve temsilcisine mesaj göndermeye çalışırsa muhtemelen çökecektir. Bunun yalnızca temsilciler gibi korunmayan ilişkiler için geçerli olduğunu unutmayın.


2
Bu mantıklı! Yine de size şunu sorayım: Sahip olduğum yaygın bir senaryo, MyController : UIViewControllerbir UIView yaratan ve sahip olan ve aynı zamanda görünümün temsilcisini kendisine ayarlayan bir sınıfa sahip olduğumdur . Bu görüşün tek alıkoyma sahibidir. Denetleyici serbest bırakıldığında, görünüm de serbest bırakılmalıdır. Delege işaretçisinin sallanmasının bir önemi var mı?
emfurry

4
@emfurry: Muhtemelen yok, çünkü görüntüleme denetleyiciniz öldüğünde görünümün kendisi görünüm hiyerarşisinde olmamalı ve hiçbir şey yapmamalı, ancak en iyisi varsayımlarda bulunmamaktır. Ya görünüm eşzamansız olarak zamanlanmış çalışma daha sonra yapılacaksa ve görünümün kendisi, görünüm denetleyicisini kısa bir süre içinde geçerse (örneğin, görünümü geçici olarak tutan zaman uyumsuz çalışma nedeniyle)? Güvende olmak için delegeyi sıfırlamak en iyisidir. Ve aslında, söz konusu görüş a UIWebViewise, dokümanlar, temsilciyi sıfırlamanız gerektiğini açıkça belirtir.
Lily Ballard

3
@zeiteisen: Hayır unsafe_unretained, bir assignözelliğe tam olarak eşdeğerdir ve MRR altındaki temsilci ilişkileri için normal davranıştır ve bunların sıfırlanması gerekir.
Lily Ballard

4
MRC ile dealloc'ta ayarlayıcıları kullanmama konusundaki ifadeye katılmıyorum. Apple bunu önermiyor ama kendi kodlarında da yapıyorlar. Ayarlayıcıyı kullanmayarak aslında yeni problemler yaratabilirsiniz. Bununla ilgili birkaç büyük tartışma var. Önemli olan, ayarlayıcıyı doğru yazmaktır (eğer ona sıfır değeri verirseniz doğru davranması gerekir) ve bazen serbest bırakma sırasını izlemektir.
Sulthan

7
@Sulthan: Dealloc'ta ayarlayıcıları kullanıp kullanmamak büyük bir solucan kutusu, ancak benim konumum temelde şu şekilde özetleniyor: dealloc'ta olabildiğince az kod çağırmak istiyorsunuz . Ayarlayıcılar, alt sınıflarda geçersiz kılarak veya KVO veya diğer mekanizmalar aracılığıyla yan etkileri dahil etme eğilimindedir. Dealloc'taki yan etkilerden özellikle veba gibi kaçınılmalıdır. Dealloc'tan bir yöntem çağrısını kaldırabiliyorsanız, bunu yapmalısınız. Bu, şu şekilde basitleştirilmiştir: dealloc'ta ayarlayıcıları çağırmayın.
Lily Ballard

2

Sadece tam tersini vermek için ...

Kısa cevap : hayır, deallocARC altında otomatik sentezlenen özellikleri sıfırlamanız gerekmez . Ve içeride olanlar için ayarlayıcı kullanmak zorunda değilsiniz init.

Uzun cevap : Sen gerektiğini de geleneksel olarak sentezlenmiş özellikler dışarı nil deallocbile ARC altında. Ve içeride olanlar için pasör kullanmalısınız init.

Önemli olan, özel sentezlenmiş özelliklerinizin geçersiz kılma açısından güvenli ve simetrik olmasıdır.

Bir zamanlayıcı için olası bir belirleyici:

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

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

Kaydırma görünümü, tablo görünümü, web görünümü, metin alanı, ... için olası bir ayarlayıcı:

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

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

KVO özelliği için olası bir ayarlayıcı:

-(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];
}

Sonra için herhangi bir kod çoğaltmak gerekmez dealloc, didReceiveMemoryWarning, viewDidUnload, ... ve mülkiyet güvenle kamuoyuna yapılabilir. Eğer mülklerin sıfırlanmasından endişeleniyorsanız dealloc, ayarlayıcılarınızı tekrar kontrol etmenin zamanı gelmiş olabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.