2009-09-07 18 views
12

What is responsible for releasing NSWindowController objects?Standart uygulamada NSWindowController sahibi kimdir?

Yeğenlerim için basit bir envanter yönetimi uygulaması yazdıktan sonra daha fazla açıklama arıyorum. "Kütüphane", vb. Içeriğini görüntüleyen bir tablo görünümüm var. Kütüphaneye yeni bir öğe eklemek için, bir '+' düğmesine tıklarlar. Bu düğme, öğenin ayrıntılarını soran yeni bir pencere açar ve 'Tamam'ı tıklattıklarında girişi doğrular.

Tüm bunlar gayet iyi çalışıyor. Ancak, bellek yönetimi hakkında bir sorum var. Yeni pencere oluşturmak için, aşağıdaki kodu kullanın:

- (IBAction)addNewItem:(id)sender { 
    LibraryItemEditorController *editorController = 
    [[LibraryItemEditorController alloc] 
      initWithWindowNibName:@"LibraryItemEditor"]; 

    [editorController showWindow:nil]; 
    // editorController is "leaked" here, it seems. 
} 

Ben serbest bırakamam (ne de sallanmasını) addNewItem: sonunda editorController, başka bir şey editorController başvuran çünkü; eğer serbest bırakırsam, pencere hemen kaybolur. Bununla birlikte, pencerenin kapatılmasından sonra pencere denetleyicisinin serbest bırakılmasını istiyorum. Apple'ın Window Programming Guide, okuduğum aşağıdaki:

o NSWindowController senin alt sınıf bir belgenin parçası olmayan zaman bir pencerenin kapatma gitmesini hem pencere ve pencere denetleyicisi yapmak istiyorsanız olarak, pencere temsilci NSWindowWillCloseNotification gözlemlemek veya olabilir, windowWillClose: yöntemini uygulamak ve uygulanmasında kod aşağıdaki satırı içerir:

[self autorelease]; 

Pencere denetleyicisinin windowWillClose: yönteminde [self autorelease] yöntemini kullandım. Bu çalışır ve hafızayı sızdırmaz. Ancak, sadece çirkin hissediyor; addNewItem: bellek sızdırıyor gibi görünüyor ve statik analiz de öyle düşünüyor. I'un aslında windowDidClose: ile ilgilendiğini biliyoruz, ancak yanlış bir şey. Dahası, pencere denetleyicisi artık kendini muhafaza etmeden kendisini serbest bırakıyor. Bu, öğrendiğim hafıza yönetimi kurallarına aykırı.

Benim diğer seçenek üst denetleyicisinde bir ivar koymaktır (ya bir NSWindowController veya NSMutableSetNSWindowController s) ve daha sonra ana denetleyicisi NSWindowWillCloseNotification izlemek ve tepki olarak bırakın. Bu daha temiz ve muhtemelen ne yapacağım. Yine de, bana sorularıma yönelten, adil bir miktar daha fazla iş var.

Bunu yapmanın standart yolu NSWindowDidCloseNotification mu? Talep üzerine oluşturulmuş ve yok edilen NSWindowControllers'un yönetilmesinin standart yolu nedir? [self autorelease] geleneksel olarak önerilen seçeneğidir ve şimdi bunun bir problem olduğu statik analizimiz var mı?

[NSApp runModalForWindow:[editorController window]]; 
[editorController release]; 

Burada olmayan kalıcı pencereler için bir model var: Pencere kalıcı olduğu gibi

cevap

5

Bu durumda, sesler

@implementation QLPrefWindowController 

+ (id) sharedInstance 
{ 
    if (!_sharedInstance) 
    { 
     _sharedInstance = [[QLPrefWindowController alloc] init]; 
    } 
    return _sharedInstance; 
} 

- (void)windowWillClose:(NSNotification *)notification 
{ 
    if ([notification object] == [self window] && self == _sharedInstance) 
    { 
     _sharedInstance = nil; 
     [self release]; 
    } 
} 
erişmek veya pencere olabilir görüntülemek isteyen

Sonra herkes +sharedInstance sınıf yöntemiyle yapın.Pencere zaten görünmüyorsa, oluşturulur, aksi halde görünür olan pencereyi alırlar.

+0

Bunu modal bir pencere olarak çalıştırmıyordum, ama sanırım muhtemelen yapmalıyım. sharedInstance sürümünün bir denetleyici paneli için anlamlı olduğunu düşünüyorum. Ve eğer birden fazla pencerenin aynı anda açılmasına gerçekten ihtiyacım olsaydı, doğrudan benim üzerimde tutmam benim için mantıklı olurdu. Bu benim için çalışıyor. –

+0

Sınıf yöntemlerinin örnek değişkenlerine erişemediği için bu yanıtın doğru olduğuna inanmıyorum. Bu durumda, "sharedInstance" sınıfı yöntemi "_sharedInstance" adında bir iVar'a erişmeye çalışır. Bu her zaman başarısız olur. – Bryan

+0

'_sharedInstance 'statik bir değişken olabilir, bir ivar değil. Bu genellikle paylaşılan örneklerin nasıl uygulandığıdır. –

0

Yukarıda belirtilen mod dışı durumlar için çözüm doğru değildir, çünkü sınıf yöntemleri iVars'a erişemez. Yukarıdaki yöntem 1 bir muhafaza sayısı ile LPWindowController örneğini döndürür

+ (id) autoreleasingInstanceShowingWindow 
{ 
    LPWindowController *obj = [[LPWindowController alloc] initWithWindowNibName:@"myWindow"]; 
    [obj showWindow:[NSApp delegate]]; 

    return obj; 
} 

Ayrıca kontrolörün penceresini gösterir: Şöyle (LPWindowController denilen benim NSWindowController alt sınıfta) bir sınıf yöntemi oluşturarak bu sorunu çözdü . Bu önemlidir, çünkü aksi takdirde LPWindowController penceresinin görünmesini sağlamak için arayanı "showWindow:" olarak çağırmak zorunda kalırdık. Arayan bunu yapmayı başaramadıysa (ki bu muhtemelen bir hata olacaktır), kontrolör asla serbest bırakılmayacaktır. Kontrolörü tahsis ettiğimiz/başlattığımız zaman pencereyi göstermeye zorlayarak, bu tuzaktan kaçınırız.

Sonraki IB biz LPWindowController sınıfa bizim pencerenin temsilci kurmak ve bu sınıfta bu ekleyin:

- (void) windowWillClose:(NSNotification *)notification 
{ 
    [self autorelease]; 
} 

Ve oluşturmak ve bizim pencere göstermek gerektiğinde son olarak, biz sadece aşağıda yöntemi kullanın LPWindowController üzerinde "alloc/initWithWindowNibName:" ifadesini çağırmak yerine.

LPWindowController *cont = [LPWindowController autoreleasingInstanceShowingWindow]; 
cont = nil; 

İkinci satır önemlidir. İlk olarak, "kullanılmayan değişken" hakkında bir uyarıyı ortadan kaldırır. İkincisi, sarkan bir işaretçinin tehlikesini ortadan kaldırır. LPWindowController örneği kendini serbest bıraktığında, devam eden bir durum yoksa, çöp belleğine işaret eder. Her neyse, bu sorun için önerilen yaklaşımım budur.