ARC

15

'da Objective-C sızıntısında yinelenen bloklar Bu yüzden özyinelemeli blokları kullanıyorum. Bir bloğun özyinelemesinin __block anahtar sözcüğünden önce gelmesi gerektiğini anlıyorum ve kopyalanmalı, böylece yığının üzerine yerleştirilebilir. Ancak, bunu yaptığımda, Enstrümanlarda bir sızıntı olarak ortaya çıkıyor. Herkesin neden ya da etrafından nasıl geçebileceğini bilen var mı? Ben diğer blokların bir sürü başvurular var ama bunların hiçbiri özyinelemeli aşağıda ARC

kodunda unutmayınız.

__block NSDecimalNumber *(^ProcessElementStack)(LinkedList *, NSString *) = [^NSDecimalNumber *(LinkedList *cformula, NSString *function){ 
     LinkedList *list = [[LinkedList alloc] init]; 
     NSDictionary *dict; 
     FormulaType type; 
     while (cformula.count > 0) { 
      dict = cformula.pop; 
      type = [[dict objectForKey:@"type"] intValue]; 
      if (type == formulaOperandOpenParen || type == formulaListOperand || type == formulaOpenParen) [list add:ProcessElementStack(cformula, [dict objectForKey:@"name"])]; 
      else if (type == formulaField || type == formulaConstant) [list add:NumberForDict(dict)]; 
      else if (type == formulaOperand) [list add:[dict objectForKey:@"name"]]; 
      else if (type == formulaCloseParen) { 
       if (function){ 
        if ([function isEqualToString:@"AVG("]) return Average(list); 
        if ([function isEqualToString:@"MIN("]) return Minimum(list); 
        if ([function isEqualToString:@"MAX("]) return Maximum(list); 
        if ([function isEqualToString:@"SQRT("]) return SquareRoot(list); 
        if ([function isEqualToString:@"ABS("]) return EvaluateStack(list).absoluteValue; 
        return EvaluateStack(list); 
       } else break; 
      } 
     } 
     return EvaluateStack(list); 
    } copy]; 
    NSDecimalNumber *number = ProcessElementStack([formula copy], nil); 

GÜNCELLEME Yani kendi araştırmalarında ben sorunu olasılıkla bu blok kullanan diğer bloklara referanslarla ilgisi var olduğunu keşfettik. Böyle basit bir şey yaparsanız, su almaması:

__block void (^LeakingBlock)(int) = [^(int i){ 
     i++; 
     if (i < 100) LeakingBlock(i); 
    } copy]; 
    LeakingBlock(1); 

Ancak, bu bir başka blok eklemek, eğer sızıntı yapar: Ben __block kullanarak denedim

void (^Log)(int) = ^(int i){ 
    NSLog(@"log sub %i", i); 
}; 

__block void (^LeakingBlock)(int) = [^(int i){ 
    Log(i); 
    i++; 
    if (i < 100) LeakingBlock(i); 
} copy]; 
LeakingBlock(1); 

Log() için anahtar kelime ve ayrıca kopyalamayı denedi, ancak hala sızdırıyor. Herhangi bir fikir?

UPDATE 2 Sızıntıyı önlemenin bir yolunu buldum, ancak biraz zahmetli. Geçilen bloğu zayıf bir kimliğe dönüştürürsem ve zayıf kimliği bir blok türüne geri döndürürsem, sızıntıyı önleyebilirim.

void (^Log)(int) = ^(int i){ 
    NSLog(@"log sub %i", i); 
}; 

__weak id WeakLogID = Log; 

__block void (^LeakingBlock)(int) = [^(int i){ 
    void (^WeakLog)(int) = WeakLogID; 
    WeakLog(i); 
    if (i < 100) LeakingBlock(++i); 
} copy]; 
LeakingBlock(1); 

Şüphesiz daha iyi bir yolu var mı?

+0

sayesinde ben de blok kopyalamak zorunda hakkında duymadım. Bununla birlikte, daha yeni bir LLVM'nin "LeakingBlock'u bu blokta güçlü bir şekilde yakalama olasılığının bir tutma döngüsüne yol açması muhtemel" çağrısında bir uyarı verdiği anlaşılmaktadır.Derleyiciyi rahatlatmak için bulduğum tek yol, aşağıdaki cevaba biraz benzer bir şekilde blok için ayrı bir zayıf ptr kullanmaktır; En son derleyiciyi denedikten sonra aldığınızı görmek isterim. –

+0

@smallduck Başlangıçta, 'copy' kullandım çünkü bloğun yığından yığına kopyalanmasını sağlıyor. Bir süre için iyi çalıştı ve ben de derleyici "özyinelemeli" hata var. "Kopyala" kodumdan kaldırdım (cevabımda yansıttığım gibi) ve işe yaradı (daha önce EXC_BAD_ACCESS olsun). Apple'ın "__block" anahtar sözcüğünü yerine yığında blok oluşturmak için değiştirdiğini tahmin ediyorum yığın ... ama bu sadece bir tahmin. –

+0

@smallduck Truthfully, özyineleme için bloklar kullanarak verdim Evet, bu yapılabilir ama biraz can sıkıcı ve çok fazla tuzak var. Döngüleri (ki bu da yineleme ile çok kötü olabilir) ve okunması zorlaşır.Çünkü ben genellikle yineleme yapmak için yöntemler/işlevlerle uğraşırız –

cevap

11

Tamam, başıma cevabını buldu ... ama teşekkürler yardım etmeye çalıştı olanlara. Eğer bir özyinelemeli bloktaki diğer bloklar kullanılarak/baþvurduðunuzu

varsa, zayıf değişkenler bunları geçmelidir. Elbette, __weak sadece işaretçi türlerini engellemek için geçerlidir, bu yüzden önce onları yazmanız gerekir. Son çözüm şu şekildedir: Yukarıdaki kod sızıntı yapmamaktadır. araştırma paylaşımı için

+1

Eğer istemiyorsanız yazım dosyasına ihtiyacınız yok: void (^ __ zayıf kayıt) (int) =^(int i) {...}; –

+2

@MattWilding İyi yakalama. Bence Xcode'un önceki sürümlerinde işe yaramadı. Derleyici, Bloklar konusunda sürekli olarak değişiyor gibi görünüyor. Ben şimdi Xcode 4.6'yı indirdim ve şimdi yukarıdaki kodun "bir" koruma döngüsüne yol açacağından şikayet ediyor. Bence Apple hala bütün "Blok" olayını çözüyor. –

+1

Blok kodumu her derleyici revizyonu ile değiştiriyorum. 4.6 ile aynı uyarıyı yaptım ve '__weak' modifer ile 'LeakingBlock' işaretleyerek bunu düzeltebilirsiniz. –

-1

ayrıca bağlam bilgi olmadan, şunu söyleyebilirim:

Sen kopyalayarak çünkü o bloğu sızıntı ve başka bir yere bırakmadan değildir. Onu yığına taşımak için kopyalamalısın, tamam. Ama seçtiğiniz yol tamamen iyi değil.

bazı nesne örneği değişken olarak saklamaktır yapmanın en doğru yolu, kopyalayın ve sonra dealloc içine bırakın. En azından, bunu sızdırmadan yapmanın bir yolu. Kodunuzdaki olarak

+2

Elle serbest bırakamıyorum ARC (otomatik referans sayımı) kullanıyorum. Bunu yapmamın nedeni, bloğun kapsamıdır, bu yüzden bir iVar kullanmak kod kokusudur. Blok, yöntemin sonunda serbest bırakılmalıdır. –

+0

ARC – Eonil

0

Aaron,

neden blok kopyalama, tek dişli gibi görünüyor? Bloğu kopyalamazsanız, bir sızıntınız olmaz.

Andrew

+0

kullanıyorsunuz Evet doğru, kod tek ben emin değilim Ancak bu beyanın amacını anlayın. Bloğu kopyalamıyorsam, blok kendiliğinden tekrar erişmeye çalıştığında EXC_BAC_ACCESS alırım. –

+1

Aslında, şunu açıklığa kavuşturmalıyım: Bloğu kopyalamadan, blok kendiliğinden yinelemeli olarak erişmeye çalıştığında (__block kullanmazsam gerçekleşir) EXC_BAD_ACCESS ataması yapılır. Ayrıntılardan biraz emin değilim, ama inanıyorum çünkü blok başlangıçta yığında bir const nesnesi olarak yaratılırken, kendi içinde başvurulan blok aynı const yığın bloğudur. Bu, bloğu önce yığına kopyalayarak ve ardından kendisini __block değerine atayarak düzeltilir, böylece kendisinin birer kopyası yerine kendisinin bir kopyasını referans alabilir. –