Bağımsız Değişkenlerle Hızlı Bloklarda Zayıf Kendini Doğru Kullanma


151

Benim TextViewTableViewCell, ben bir blok izlemek için bir değişken ve blok geçirilir ve atanmış bir yapılandırma yöntemi var.
İşte benim TextViewTableViewCellsınıfım:

//
//  TextViewTableViewCell.swift
//

import UIKit

class TextViewTableViewCell: UITableViewCell, UITextViewDelegate {

    @IBOutlet var textView : UITextView

    var onTextViewEditClosure : ((text : String) -> Void)?

    func configure(#text: String?, onTextEdit : ((text : String) -> Void)) {
        onTextViewEditClosure = onTextEdit
        textView.delegate = self
        textView.text = text
    }

    // #pragma mark - Text View Delegate

    func textViewDidEndEditing(textView: UITextView!) {
        if onTextViewEditClosure {
            onTextViewEditClosure!(text: textView.text)
        }
    }
}

Metodumda configure yöntemini kullandığımda, geçtiğim cellForRowAtIndexPathblokta zayıf benliği nasıl düzgün bir şekilde kullanabilirim.
İşte zayıf benlik olmadan sahip olduğum şey:

let myCell = tableView.dequeueReusableCellWithIdentifier(textViewCellIdenfitier) as TextViewTableViewCell
myCell.configure(text: body, onTextEdit: {(text: String) in
   // THIS SELF NEEDS TO BE WEAK  
   self.body = text
})
cell = bodyCell

GÜNCELLEME : Aşağıdakileri kullanarak çalışmak için aşağıdakileri aldım [weak self]:

let myCell = tableView.dequeueReusableCellWithIdentifier(textViewCellIdenfitier) as TextViewTableViewCell
myCell.configure(text: body, onTextEdit: {[weak self] (text: String) in
        if let strongSelf = self {
             strongSelf.body = text
        }
})
cell = myCell

Ben [unowned self]yerine yapmak [weak self]ve ifade almak if, uygulama çöküyor. Bunun nasıl çalışması gerektiği hakkında bir fikriniz var [unowned self]mı?


Doğru cevabı olarak aşağıdaki cevabı seçebilir misiniz? Ayrıca, sahipsiz durumdayken, kapanışınız içinde kendini güçlendirmeniz gerekmeyeceğini unutmayın. Unowned burada zayıf daha iyidir çünkü hücre ve görünüm denetleyicinizin yaşam döngüsü bağlantılı.
ikuramedia

1
Ben daha iyi bir seçenek [sahipsiz ben] olduğunu fark, ama benim app kullandığımda çöküyor. Cevabı kapatmak için kullanarak bir kod örneği görmek isterim.
NatashaTheRobot

1
Dokümanlardan: "Zayıf referanslar gibi, bilinmeyen bir referans, atıfta bulunduğu örnek üzerinde güçlü bir bekletme yapmaz. Ancak zayıf bir referansın aksine, bilinmeyen bir referansın her zaman bir değere sahip olduğu varsayılır." çünkü sahipsiz, çalışma zamanında sıfır değerine uygulanmaktadır.
Bill Patterson

Muhtemelen burada bir guard ifadesinin reklamını yapmak için strongSelf'e bağlanmasına izin verin. Sadece söyleyerek, bu mükemmel bir aday gibi :-D
Daniel Galasko

@NatashaTheRobot, [zayıf benlik] sözdizimi nedir? Hedef C'den geçen bir mesaj gibi görünüyor. Lütfen sorudaki sözdizimi hakkında biraz daha bilgi ekleyebilir misiniz lütfen.
Vignesh

Yanıtlar:


178

Eğer benlik kapanmada sıfır olabilirse [zayıf benlik] kullanın .

Eğer kapanışta benlik asla sıfır olmazsa [sahipsiz benlik] kullanın .

Eğer [sahipsiz kendilik] kullandığınızda çöküyorsa, ben bu kapanışta bir noktada kendinizin sıfır olduğunu tahmin ederdim, bu yüzden onun yerine [zayıf kendilik] ile gitmek zorunda kaldınız.

Güçlü , zayıf ve kapaksız olarak kullanma kılavuzundaki tüm bölümü gerçekten beğendim :

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html

Not: Daha yeni Swift terimi olan blok yerine kapatma terimini kullandım:

İOS'ta blok (Amaç C) ve kapatma (Swift) arasındaki fark


7
Apple, C dil uzantısı için ilk belgelerinde blokları "kapatmalar" olarak adlandırdı. (Bloklar veya kapaklar ilk başta C'nin bir uzantısıdır. Yalnızca MM Objective-C ile ilgilidir.) Ben de "kapatma" terimini tercih etsem de, çünkü C'deki "bloklar" bileşik ifadelerle çok sık ilişkilidir, her iki dilde de bir tür yanlıştır, çünkü bir nesnenin (değişken veya sabit) üzerine kapanmasa bile kapanma olarak adlandırılır.
Amin Negm-Awad

1
çok güzel cevap verdi :)
iDevAmit

1
Hiç kullanmamayı öneririm unowned. Uygulamanızın çökmesine neden olma riskine değmez.
Kyle Redfearn

32

Daha [unowned self]önce (text: String)...kapanışına koy . Buna yakalama listesi denir ve sahiplik talimatlarını kapakta yakalanan sembollere yerleştirir.


2
İsimlendirdiğiniz için teşekkürler, bunu bilmek istedim!
rob5408

3
Bu cevabın yararlı olduğunu düşünmüyorum. kapatma işlemi sırasında kendini sıfırlarsa [sahipsiz ben]
çökecektir

3
bilinmeyen (1) son derece alışılmadık durumlarda, performans için (burada ve programlamanın% 99,999'unda bu tamamen önemsizdir) ve (2) bir stil uygulama meselesi olarak kullanılması için kesinlikle hiçbir neden yoktur . "Her zaman zayıf, hiç sahipsiz kullanmalısınız" ifadesi çok makul.
Fattie

29

** Swift 4.2 için düzenlenmiş:

@Koen'in yorumladığı gibi, hızlı 4.2 şunları sağlar:

guard let self = self else {
   return // Could not get a strong reference for self :`(
}

// Now self is a strong reference
self.doSomething()

Not: Bazı oylama yaptığımdan, kaçan kapanışlarla ilgili okumayı tavsiye etmek istiyorum .

DÜZENLENEN: @ tim-vermeulen yorumladığı gibi, Chris Lattner 22 Ocak 19:51:29 CST 2016 tarihinde, bu hile kendi başına kullanılmamalıdır, bu yüzden lütfen kullanmayın. @Gbk'den kaçmayan kapanış bilgilerini ve yakalama listesi yanıtını kontrol edin. **

Yakalama listesinde [zayıf benlik] kullananlar için, benliğin sıfır olabileceğine dikkat edin, bu yüzden yaptığım ilk şey bunu bir bekçi ifadesiyle kontrol etmek.

guard let `self` = self else {
   return
}
self.doSomething()

Eğer merak ediyorsanız neyi alıntı işaretleri etrafında selfadını değiştirmeye gerek kalmadan kapatılması iç kullanım kendine yanlısı bir hiledir bu , weakSelf ya da her neyse.


2
`` self '' bir gölgeleme örneğidir, bunun hakkında bir makale burada bulunabilir arsenkin.com/swift-closure-without-ugly-strongSelf.html
Cullen SUN

2
Varsayılan kendilik ile karıştırılmadığından ve güçlü bir öz referans için korunup korunmadığınızı tespit etmenin daha kolay olduğundan emin olmak için yerel "öz" "güçlüKendi" adını verme eğilimindeyim.
Justin Stanley

1
Bir derleyici hatası olduğu için bu kullanılmamalıdır: lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160118/…
Tim Vermeulen

1
Yukarıdaki linkte Chris Lattner tarafından yapılan yorum sadece değişkeni self(backticks olarak) olarak adlandırmamakla ilgili olduğunu düşünüyorum . Ona nonOptionalSelf gibi başka bir ad verin ve iyi olacak.
OutOnAWeekend

1
Günümüzde (hızlı 4.2) { [weak self] in guard let self = self else { return }ters çentik olmadan kullanılabilir ve aslında desteklenir: github.com/apple/swift-evolution/blob/master/proposals/…
Koen.

26

Yakalama listesini kullan

Bir Yakalama Listesi Tanımlama

Yakalama listesindeki her öğe, zayıf veya bilinmeyen anahtar kelimenin, bir sınıf örneğine (self gibi) veya bir değerle (delegate = self.delegate!) Başlatılmış bir değişkene referansla eşleştirilmesidir. Bu eşlemeler virgülle ayrılmış bir çift kare parantez içinde yazılır.

Yakalama listesini bir kapanışın parametre listesinden önce yerleştirin ve sağlandıysa dönüş türünü yazın:

lazy var someClosure: (Int, String) -> String = {
    [unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
    // closure body goes here 
} 

Kapatma, bağlamdan çıkarılabildikleri için bir parametre listesi veya dönüş türü belirtmezse, yakalama listesini kapağın en başına, ardından in anahtar sözcüğüne yerleştirin:

lazy var someClosure: Void -> String = {
    [unowned self, weak delegate = self.delegate!] in
    // closure body goes here
}

ek açıklamalar


3
"Ben" için sahipsiz kullandığınız anlamına gelir, yani "ben" eriştiğinizde sıfır olmayacaktır. Sonra zayıf bir var atamak için "self.delegate" (bu da sıfır olmayacağından emin olduğunuz anlamına da gelir) kuvvet çözme kullandınız. Eğer "self.delegate" in sıfır olmayacağından eminseniz, neden zayıf yerine "delege" ye sahipsiz kullanmıyorsunuz?
Roni Leshes

26

EDIT: LightMan tarafından güncellenmiş bir çözüm referansı

LightMan'ın çözümüne bakın . Şimdiye kadar kullanıyordum:

input.action = { [weak self] value in
    guard let this = self else { return }
    this.someCall(value) // 'this' isn't nil
}

Veya:

input.action = { [weak self] value in
    self?.someCall(value) // call is done if self isn't nil
}

Genellikle çıkarılırsa parametre türünü belirtmeniz gerekmez.

Parametreyi yoksa veya $0kapatmadaki gibi başvurursanız parametreyi tamamen atlayabilirsiniz :

input.action = { [weak self] in
    self?.someCall($0) // call is done if self isn't nil
}

Sadece bütünlük için; kapatmayı bir işleve geçiriyorsanız ve parametre değilse @escaping, aşağıdakilere ihtiyacınız yoktur weak self:

[1,2,3,4,5].forEach { self.someCall($0) }

9

Hızlı 4.2'den itibaren şunları yapabiliriz:

_ = { [weak self] value in
    guard let self = self else { return }
    print(self) //👈 will never be nil
}()

Diğerleri benzer çözümlere sahiptir, ancak "bu" C ++ IMHO'dur. "strongSelf" bir Apple sözleşmesidir ve kodunuza bakan herkes neler olup bittiğini bilecektir.
David H

1
@ David H IMO cümle strongSelf, kodun daha uzun bir doğaya sahip olması durumunda güzel olan anlam / yan etki değişkenlerini açıkça açıklar. fikriniz için teşekkür ederiz, c ++ böyle ifade kullanılan bilmiyordum.
eonist

3
Swift 4.2'den itibarenguard let self = self else { return } paketini açmak için kullanabilirsiniz [weak self]: github.com/apple/swift-evolution/blob/master/proposals/…
Amer Hukic

@AmerHukic 👌.
eonist


3

Blok parametrelerinizden önce yakalama listesinde [zayıf benlik] veya [sahipsiz benlik] kullanabilirsiniz. Yakalama listesi isteğe bağlı sözdizimidir.

[unowned self]burada iyi çalışır çünkü hücre asla sıfır olmaz. Aksi takdirde kullanabilirsiniz[weak self]


1
Hücre kendiliğinden değil, hücre sınıfında değil, muhtemelen bir vizör denetleyicide ...
Juan Boero

0

Eğer çöküyorsanız muhtemelen [zayıf benliğe] ihtiyacınız var

Tahminimce, oluşturduğunuz blok bir şekilde hala bağlı.

PreparForReuse oluşturun ve içindeki onTextViewEditClosure bloğunu temizlemeyi deneyin.

func prepareForResuse() {
   onTextViewEditClosure = nil
   textView.delegate = nil
}

Bunun çökmeyi önleyip önlemediğine bakın. (Bu sadece bir tahmin).


0

Kapatma ve güçlü referans çevrimleri [Hakkında]

Bildiğiniz gibi Swift'in kapanışı örneği yakalayabilir. Bu, selfbir kapak içinde kullanabileceğiniz anlamına gelir . Özellikle escaping closure[Hakkında] bir tane strong reference cycleoluşturabilir. Bu arada selfiçeride açıkça kullanmanız gerekiyorescaping closure .

Hızlı kapatma, Capture Listyakalanan örnek için güçlü bir referansa sahip olmadığından, bu durumdan kaçınmanıza ve bir referans döngüsünü kırmanıza izin veren bir özelliğe sahiptir. Yakalama Listesi öğesi bir weak/unowned ve sınıf veya değişkene bir referanstır.

Örneğin

class A {
    private var completionHandler: (() -> Void)!
    private var completionHandler2: ((String) -> Bool)!

    func nonescapingClosure(completionHandler: () -> Void) {
        print("Hello World")
    }

    func escapingClosure(completionHandler: @escaping () -> Void) {
        self.completionHandler = completionHandler
    }

    func escapingClosureWithPArameter(completionHandler: @escaping (String) -> Bool) {
        self.completionHandler2 = completionHandler
    }
}

class B {
    var variable = "Var"

    func foo() {
        let a = A()

        //nonescapingClosure
        a.nonescapingClosure {
            variable = "nonescapingClosure"
        }

        //escapingClosure
        //strong reference cycle
        a.escapingClosure {
            self.variable = "escapingClosure"
        }

        //Capture List - [weak self]
        a.escapingClosure {[weak self] in
            self?.variable = "escapingClosure"
        }

        //Capture List - [unowned self]
        a.escapingClosure {[unowned self] in
            self.variable = "escapingClosure"
        }

        //escapingClosureWithPArameter
        a.escapingClosureWithPArameter { [weak self] (str) -> Bool in
            self?.variable = "escapingClosureWithPArameter"
            return true
        }
    }
}
  • weak- daha çok tercih edilir, mümkün olduğunda kullanın
  • unowned - örnek sahibinin kullanım ömrünün kapanıştan daha büyük olduğundan emin olduğunuzda kullanın
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.