Zayıf bir referans ile bilinmeyen bir referans arasındaki fark nedir?


240

Swift şunları içerir:

  • Güçlü Referanslar
  • Zayıf Referanslar
  • Sahipsiz Referanslar

Sahipsiz bir referansın zayıf referanstan farkı nedir?

Sahipsiz bir referans kullanmak ne zaman güvenlidir?

Sahipsiz referanslar C / C ++ 'da sarkan işaretçiler gibi bir güvenlik riski midir?



Deneyimlerim, unownedkontrol ettiğimiz sınıflar için, Apple sınıfları için kullanmaktır, weakçünkü ne yaptığından emin
olamayız

@NoorAli veya "sahipsiz" referansı olarak "ownedBy" genellikle sahibine işaret eder.
Ian Ringrose

1
NOT: Bu referansların her birinde dikkat edilmesi gereken önemli performans sonuçları vardır: stackoverflow.com/questions/58635303/…
Epik Bayt

@EpicByte Bazen Java veya C # gibi tam bir GC ek yüke değer.
Ian Ringrose

Yanıtlar:


361

Hem weakve unownedreferanslar bir oluşturmayın strong(bunlar sevk nesne ayırmayı kaldırma engelle ARC amacıyla sayımı korumak artmadığını aka) sevk nesne üzerinde tutun.

Peki neden iki anahtar kelime? Bu ayrım, Optionaltürlerin Swift dilinde yerleşik olması gerçeğiyle ilgilidir . Uzun hikaye kısa: isteğe bağlı türler bellek güvenliği sunar (bu, Swift'in yapıcı kurallarıyla güzel çalışır - bu fayda sağlamak için katıdır).

Bir weakbaşvuru, nil(başvurulan nesne yeniden konumlandırıldığında bu otomatik olarak gerçekleşir) olasılığına izin verir , bu nedenle mülkünüzün türü isteğe bağlı olmalıdır - bu nedenle, bir programcı olarak, onu kullanmadan önce kontrol etmeniz gerekir (temelde derleyici sizi olabildiğince güvenli kod yazmaya zorlar).

Bir unownedreferans nil, ömrü boyunca asla olmayacağını varsayar . Başlatma sırasında bilinmeyen bir referans ayarlanmalıdır - bu, referansın kontroller olmadan güvenle kullanılabilecek isteğe bağlı olmayan bir tür olarak tanımlanacağı anlamına gelir. Bir şekilde atıfta bulunulan nesne yeniden konumlandırılırsa, sahipsiz referans kullanıldığında uygulama kilitlenir.

Gönderen Elma docs :

Bu başvurunun kullanım ömrü boyunca bir noktada sıfır olması geçerli olduğunda zayıf bir başvuru kullanın. Bunun tersine, başvurunun başlatma sırasında ayarlandıktan sonra hiçbir zaman sıfır olmayacağını bildiğinizde bilinmeyen bir referans kullanın.

Dokümanlarda, tutma döngülerini ve bunların nasıl kırılacağını tartışan bazı örnekler vardır. Tüm bu örnekler dokümanlardan çıkarılmıştır .

weakAnahtar kelime örneği :

class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
}

class Apartment {
    let number: Int
    init(number: Int) { self.number = number }
    weak var tenant: Person?
}

Ve şimdi, bazı ASCII sanatı için (gitmeli belgeleri görmelisiniz - güzel diyagramları var):

Person ===(strong)==> Apartment
Person <==(weak)===== Apartment

PersonVe Apartmentörneğin Şekil sıfır olarak izin verilen, her ikisi de, iki özellik, güçlü bir referans döngüsü neden olma potansiyeline sahip bir durumdur. Bu senaryo en iyi şekilde zayıf bir referansla çözülür. Her iki varlık da diğerine sıkı bir bağımlılık göstermeden var olabilir.

unownedAnahtar kelime örneği :

class Customer {
    let name: String
    var card: CreditCard?
    init(name: String) { self.name = name }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer
    init(number: UInt64, customer: Customer) { self.number = number; self.customer = customer }
}

Bu örnekte, a bir Customerolabilir veya olmayabilir CreditCard, ancak a CreditCard her zaman a ile ilişkilendirilir Customer. Bunu temsil etmek için, Customersınıfın isteğe bağlı bir cardözelliği vardır, ancak CreditCardsınıfın isteğe bağlı olmayan (ve sahipsiz) bir customerözelliği vardır.

Customer ===(strong)==> CreditCard
Customer <==(unowned)== CreditCard

CustomerVe CreditCardörneğin Şekil, bir sıfır olarak bırakılır özelliği ve sıfır olamaz başka bir özelliği, bir güçlü bir referans döngüsü neden olma potansiyeline sahip olan bir durum. Bu senaryo, en iyi şekilde bilinmeyen bir referansla çözülür.

Apple'dan not:

Zayıf referanslar, değerlerinin çalışma zamanında değişebileceğini belirtmek için değişken olarak bildirilmelidir. Zayıf bir referans sabit olarak ilan edilemez.

Her iki özelliğin de her zaman bir değere sahip olması ve başlatma tamamlandıktan sonra hiçbir özelliğin sıfır olmaması gereken üçüncü bir senaryo da vardır.

Ayrıca, kapaklarla çalışırken kaçınılması gereken klasik tutma döngüsü senaryoları da vardır.

Bunun için Apple belgelerini ziyaret etmenizi veya kitabı okumanızı tavsiye ederim .


3
Bu biraz önemsiz ama Daire ve Kişi örneğini biraz kafa karıştırıcı buluyorum, bu da güçlü referans döngüsünü kırmak için ek bir çözüm sunuyor. Bir kişinin dairesi isteğe bağlıdır ve bu nedenle bir dairenin kiracısının isteğe bağlı olduğu kadar sıfır olabilir ve bu nedenle sıfır olabilir, böylece her iki özellik de zayıf olarak tanımlanabilir. ``
Justin Levi Winter

sınıf Kişi {let name: String init (name: String) {self.name = name} zayıf var daire: Apartman? } sınıf Daire {let numarası: Int init (sayı: Int) {self.number = number} zayıf değişken kiracı: Kişi? }
Justin Levi Winter

3
Arasındaki fark nedir weak var Person?vs. var Person??
Dean

4
@ JustinLevi, Her iki özelliği de zayıf olarak beyan ederseniz, bunların yeniden konumlandırılma olasılığı vardır. Daire taşınmayacak kişi daire güçlü bir referans tutar. Daire Kişiye karşı aynı güçlü referansa sahip olacaksa, bir tutma döngüsü oluşturacaklardı - bu, programcı tarafından bilirse çalışma zamanında kırılabilir, ancak aksi takdirde sadece bir bellek sızıntısı olur. Bu, güçlü, zayıf ve sahipsiz hakkında yaygara: daha yüksek düzeyde bellek yönetimi, çünkü ARC bizim için tüm kirli şeyleri yapıyor. Koruma döngülerinden kaçınmak bizim işimiz.
Ilea Cristian

1
Sahipsizin zayıf olanın tek yararı, paketini açmanıza gerek kalmaması ve sabit kullanabilmeniz mi? Zayıf kullanamayacağınız ve sadece sahipsiz kullanabileceğiniz herhangi bir örnek var mı?
Alan

29

S1. “Sahipsiz referans” ın “Zayıf Referans” dan farkı nedir?

Zayıf Referans:

Zayıf bir başvuru, atıfta bulunduğu örnek üzerinde güçlü bir beklemeye sahip olmayan ve bu nedenle ARC'nin başvuruda bulunulan örneğin atılmasını durdurmayan bir başvurudır. Zayıf referansların “değersiz” olmasına izin verildiğinden, her zayıf referansı isteğe bağlı bir tür olarak bildirmeniz gerekir. (Apple Dokümanları)

Sahipsiz Referans:

Zayıf referanslar gibi, bilinmeyen referans da atıfta bulunduğu örnek üzerinde güçlü bir beklemeye sahip değildir. Ancak zayıf bir referanstan farklı olarak, bilinmeyen bir referansın her zaman bir değere sahip olduğu varsayılır. Bu nedenle, sahipsiz bir başvuru her zaman isteğe bağlı olmayan bir tür olarak tanımlanır. (Apple Dokümanları)

Her Biri Ne Zaman Kullanılmalı:

Bu başvurunun kullanım ömrü boyunca bir noktada sıfır olması geçerli olduğunda zayıf bir başvuru kullanın. Bunun tersine, başvurunun başlatma sırasında ayarlandıktan sonra asla sıfır olmayacağını bildiğinizde bilinmeyen bir referans kullanın. (Apple Dokümanları)


S2. “Sahipsiz referans” kullanmak ne zaman güvenlidir?

Yukarıda belirtildiği gibi, sahipsiz bir referansın her zaman bir değere sahip olduğu varsayılır. Bu yüzden sadece referansın asla sıfır olmayacağından eminseniz kullanmalısınız. Apple Docs, aşağıdaki örnekte bilinmeyen referanslar için bir kullanım durumunu göstermektedir.

İki sınıfları olduğunu varsayalım Customerve CreditCard. Bir müşteri kredi kartı olmadan var olabilir, ancak müşteri olmadan kredi kartı bulunmayacaktır, yani bir kredi kartının her zaman bir müşterisi olacağı varsayılabilir. Yani, aşağıdaki ilişkiye sahip olmalılar:

class Customer {
    var card: CreditCard?
}

class CreditCard {
    unowned let customer: Customer
}

Q3. “Sahipsiz referans” referansı, C / C ++ 'da “sarkan işaretçiler” gibi bir güvenlik riski midir?

Ben öyle düşünmüyorum.

Sahipsiz referanslar sadece bir değeri olduğu garanti edilen zayıf referanslar olduğundan, hiçbir şekilde bir güvenlik riski olmamalıdır. Bununla birlikte, başvurduğu referans dağıtıldıktan sonra sahipsiz bir referansa erişmeye çalışırsanız, bir çalışma zamanı hatası tetiklersiniz ve uygulama kilitlenir.

Onunla gördüğüm tek risk bu.

Apple Dokümanlarına Bağlantı


senin Q2 örnek programı basit hakkında bilinmeyen .. teşekkürler .. zayıf ve güçlü için aynı türde bir örnek ekleyebilir miyim ..
Ranjith Kumar

Mükemmel. Teşekkür ederim.
Swifty McSwifterton

Sahipsiz veya zayıf olanlar için ortak bir örnek verebilir misiniz?
Bal

Üst ve alt nesneleri göz önünde bulundurun; alt öğe üst öğe olmadan var olamazsa unowned, alt sınıftaki üst öğenin özelliği için kullanın . zayıf tam tersi. Güzel açıklama @ myxtic! unownedreferanslar sadece weakbir değeri olduğu garanti edilen referanslardır!
Saif

26

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 .

[Sahipsiz benlik] kullandığınızda çöküyorsa, o zaman muhtemelen bu kapanışın bir noktasında sıfırdır ve muhtemelen bunun yerine [zayıf benlik] kullanmanız gerekir.

Kapatmalarda güçlü , zayıf ve bilinmeyen kullanma ile ilgili örnekleri inceleyin :

https://developer.apple.com/library/ios/documentation/swift/conceptual/swift_programming_language/AutomaticReferenceCounting.html


7
Kendini asla sıfır olmasa bile neden zayıf kullanmıyorsun?
Boon

4
merhaba @Boon - bu gerçekten kritik bir soru.
Fattie

[zayıf benlik] => viewDidLoad () içinde kapatma kullanırsam, selfnil nasıl olabilir ?
Hassan Tareq

@HassanTareq, bence yukarıda bahsedilen makalede birkaç iyi örnek belirtilmiştir. "Kapanışlar için Güçlü Referans Döngülerini Çözme" bölümünü kontrol edin, esp. Alıntı: "Swift, bir kapatma içinde kendi kendine bir üyeye başvurduğunuzda self.someProperty veya self.someMethod () (yalnızca someProperty veya someMethod () yerine) yazmanızı gerektirir. Bu, kaza." Alıntı: Apple Inc. “Hızlı Programlama Dili (Swift 4).” iBooks. itunes.apple.com/de/book/the-swift-programming-language-swift-4/... "
Nick Entin

1
@Boon Her zaman zayıf kullanırsanız, derleyici kullanmadan önce isteğe bağlı olup olmadığını kontrol etmeye zorlar. Bu kontrolü siz koymadıysanız, derleme zamanı hatası verecektir. Başka Zarar yok.
Vikas Mishra

5

Bağlantıdan alıntılar

Birkaç Sonuç puanı

  • Güçlü, zayıf veya bilinmeyen hakkında endişelenmeniz gerekip gerekmediğini belirlemek için “Referans türleriyle ilgileniyor muyum?” Diye sorun. Structs veya Enums ile çalışıyorsanız, ARC bu Türler için belleği yönetmez ve bu sabitler veya değişkenler için zayıf veya bilinmeyen belirtme konusunda endişelenmenize bile gerek yoktur.
  • Güçlü referanslar, ebeveynin çocuğa referans verdiği hiyerarşik ilişkilerde iyidir, bunun tersi değildir. Aslında, güçlü referanslar çoğu zaman en uygun referans türüdür.
  • İki örnek isteğe bağlı olarak birbiriyle ilişkili olduğunda, bu örneklerden birinin diğerine zayıf bir referansı olduğundan emin olun.
  • İki örnek, örneklerden biri diğeri olmadan var olamayacak şekilde ilişkili olduğunda, zorunlu bağımlılığa sahip olan örneğin diğer örneğe sahipsiz bir referansı tutması gerekir.

1

Hem weakve unownedreferanslar nesnenin başvuru sayısını etkilemeyecektir. Ancak zayıf referans her zaman isteğe bağlı olacaktır, yani sıfır olabilirken, unownedreferanslar asla sıfır olamaz , bu yüzden asla isteğe bağlı olamazlar. İsteğe bağlı bir referans kullanırken, nesnenin sıfır olma olasılığını her zaman ele almanız gerekir. Bilinmeyen bir başvuru durumunda, nesnenin asla sıfır olmadığından emin olmanız gerekir. Nil nesnesine sahipsiz bir başvuru kullanmak, nil olan isteğe bağlı bir öğeyi zorla açmaya benzer.

Bu, nesnenin ömrünün referansınkinden daha fazla olduğundan emin olduğunuz, sahipsiz bir referans kullanmanın güvenli olduğunu söyledi. Durum böyle değilse, bunun yerine zayıf bir referans kullanmak daha iyidir.

Sorunun üçüncü bölümüne gelince, sahipsiz referansın sarkan bir işaretçiye benzediğini düşünmüyorum. Referans sayımı hakkında konuştuğumuzda, genellikle nesnenin güçlü referans sayımından bahsederiz. Benzer şekilde hızlıca, nesnenin sahipsiz referans sayısını ve zayıf referans sayısını korur (zayıf referans, nesnenin kendisi yerine "yan tablo" olarak adlandırılan bir şeye işaret eder). Güçlü referans sayısı sıfıra ulaştığında, nesne kaldırılır, ancak sahipsiz referans sayısı sıfırdan büyükse yeniden konumlandırılamaz.

Artık sarkan bir işaretçi, önceden yerleştirilmiş olan bir bellek konumuna işaret eden bir şeydir. Ancak, bellek yalnızca nesneye bilinmeyen bir referans olduğu sürece yeniden yerleştirilebildiğinden, sarkan bir işaretçiye neden olamaz.

Hızlı bellek yönetimini daha ayrıntılı olarak tartışan birçok makale vardır. İşte bir tane.


0

Sahipsiz başvurular, bir nesnenin yalnızca başka bir nesneye ait olması gerektiğinde, iki nesne arasındaki Aynı Ömür Boyu ilişki durumunda kullanılan bir tür zayıf referanstır. Bir nesne ve özelliklerinden biri arasında değişmez bir bağ yaratmanın bir yoludur.

Ara hızlı WWDC videosunda verilen örnekte, bir kişinin kredi kartı vardır ve kredi kartının yalnızca bir sahibi olabilir. Kredi kartında, kişi yalnızca isteğe bağlı bir mülk olmamalıdır, çünkü yalnızca bir sahiple kredi kartının çevrilmesini istemezsiniz. Kredi üzerindeki holder özelliğini zayıf bir referans haline getirerek bu döngüyü kırabilirsiniz, ancak bu aynı zamanda isteğe bağlı ve değişken (sabitin aksine) yapmanızı gerektirir. Bu durumda sahipsiz referans, CreditCard'ın bir Kişiye ait bir hissesi olmamasına rağmen, ömrünün ona bağlı olduğu anlamına gelir.

class Person {
    var card: CreditCard?
}

class CreditCard {

    unowned let holder: Person

    init (holder: Person) {
        self.holder = holder
    }
}

wwdc video veya başlık bağlantısı?
Osa

-2

O noktaya asla eriştiğiniz noktada olamayacağınızdan unownedemin olduğunuzda kullanın .selfnilself

Örnek (elbette hedefi doğrudan içinden ekleyebilirsiniz MyViewController, ancak yine de basit bir örnek):

class MyViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let myButton = MyButton { [unowned self] in
            print("At this point, self can NEVER be nil. You are safe to use unowned.")
            print("This is because myButton can not be referenced without/outside this instance (myViewController)")
        }
    }
}

class MyButton: UIButton {
    var clicked: (() -> ())

    init(clicked: (() -> ())) {
        self.clicked = clicked

        // We use constraints to layout the view. We don't explicitly set the frame.
        super.init(frame: .zero)

        addTarget(self, action: #selector(clicked), for: .touchUpInside)
    }

    @objc private func sendClosure() {
        clicked()
    }
}

Kullanım weakolasılığı vardır ne zaman selfolabilir nilErişmekte noktada self.

Misal:

class MyViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        NetworkManager.sharedInstance.receivedData = { [weak self] (data) in
            print("Can you guarentee that self is always available when the network manager received data?")
            print("Nope, you can't. Network manager will be alive, regardless of this particular instance of MyViewController")
            print("You should use weak self here, since you are not sure if this instance is still alive for every")
            print("future callback of network manager")
        }
    }
}

class NetworkManager {

    static let sharedInstance = NetworkManager()

    var receivedData: ((Data) -> ())?

    private func process(_ data: Data) {
        // process the data...

        // ... eventually notify a possible listener.
        receivedData?(data)
    }
}

Eksileri unowned:

  • Zayıftan daha verimli
  • Örneği değiştirilemez olarak işaretleyebilirsiniz (artık zorlanıyorsunuz) (artık Swift 5.0'dan beri değil).
  • Kodunuzun okuyucusunu gösterir: Bu örneğin X ile bir ilişkisi vardır ve onsuz yaşayamaz, ancak X gittiğinde ben de gittim.

Eksileri weak:

  • Sahipsiz olduğundan daha güvenli (çökemediğinden).
  • X ile her iki yönde de ilişki kurabilir, ancak her ikisi de birbiri olmadan yaşayabilir.

Emin değilseniz kullanın weak. Bekle , yani StackOverflow'da davanızda ne yapmanız gerektiğini sorun! Yapmamanız gereken her zaman zayıf kullanmak sadece sizin ve kodunuzun okuyucusu için kafa karıştırıcıdır.

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.