'Pure' Swift'te zayıf bir protokol başvurusunu nasıl yapabilirim (@objc olmadan)


561

weakreferanslar , saf bir Swift uygulamasında istemediğim bir a protocololarak belirtilmedikçe Swift'te çalışmıyor gibi görünüyor @objc.

Bu kod bir derleme hatası verir ( weaksınıf dışı türe uygulanamaz MyClassDelegate):

class MyClass {
  weak var delegate: MyClassDelegate?
}

protocol MyClassDelegate {
}

Protokol ile önek gerekir @objc, sonra çalışır.

Soru: Bir başarmanın 'saf' Swift yolu weak delegatenedir?


Yanıtlar:


1038

Protokol türünü bildirmeniz gerekir AnyObject.

protocol ProtocolNameDelegate: AnyObject {
    // Protocol stuff goes here
}

class SomeClass {
    weak var delegate: ProtocolNameDelegate?
}

AnyObjectBunu kullanarak , yalnızca sınıfların bu protokole uyduğunu söylerken, yapılar veya numaralandırmalar yapamaz.


25
Bu çözümlerle ilgili sorunum, temsilci çağırmanın bir çökmeye neden olması - EXC_BAD_ACCESS (başkaları tarafından başka yerlerde belirtildiği gibi). Bu bir hata gibi görünüyor. Bulduğum tek çözüm @objc kullanmak ve tüm Swift veri türlerini protokolden kaldırmaktır.
Jim T

12
Swift'te şu anda zayıf delegeler yapmanın doğru yolu nedir? Apple belgeleri, temsilciyi örnek kodlarında zayıf olarak göstermiyor veya
bildirmiyor

2
Bu her zaman güvenli değildir - delegeyi yalnızca temsilci için bir referans tutarsa ​​ve bu güçlü referans döngüsünü kırmanız gerekiyorsa zayıflatmanız gerektiğini unutmayın. Delege temsilci için herhangi bir referansa sahip değilse, temsilci kapsam dışında kalabilir (çünkü zayıftır) ve çökmeler ve diğer sorunlar yaşayabilirsiniz: / akılda tutulması gereken bir şey.
Trev14

5
BTW: Bence "yeni stil" (Swift 5) yapmak protocol ProtocolNameDelegate: AnyObjectama önemli değil.
hnh

1
O AnyObjectzamandan beri classbir noktada kullanımdan kaldırılacak.
José

283

Tamamlayıcı Cevap

Delegelerin zayıf olup olmayacağı konusunda hep kafam karıştı. Son zamanlarda delegeler ve zayıf referansların ne zaman kullanılacağı hakkında daha fazla şey öğrendim, bu yüzden gelecekteki izleyiciler uğruna bazı ek noktalar ekleyeyim.

  • weakAnahtar kelimeyi kullanmanın amacı, güçlü referans döngülerinden (koruma döngüleri) kaçınmaktır . Güçlü referans döngüleri, iki sınıf örneğinin güçlü referansları olduğunda meydana gelir. Referans sayıları hiçbir zaman sıfıra gitmez, bu yüzden asla yeniden konumlandırılmazlar.

  • Yalnızca weaktemsilci bir sınıfsa kullanmanız gerekir . Swift yapıları ve sıralamaları referans türleri değil, değer türleridir (değerleri yeni bir örnek oluşturulduğunda kopyalanır), bu nedenle güçlü başvuru döngüleri oluşturmazlar.

  • weakreferanslar her zaman isteğe bağlıdır (aksi takdirde kullanırsınız unowned) ve her zaman var(değil let) nilkullanırsınız;

  • Bir ebeveyn sınıfının doğal olarak alt sınıflarına güçlü bir referansı olmalı ve bu nedenle weakanahtar kelimeyi kullanmamalıdır . Bir çocuk ebeveynine referans istediğinde, weakanahtar kelimeyi kullanarak zayıf bir referans yapmalıdır .

  • weakyalnızca üst öğeye başvuran bir çocuk için değil, sahip olmadığınız bir sınıfa başvuru yapmak istediğinizde kullanılmalıdır. Hiyerarşik olmayan iki sınıfın birbirlerine başvurması gerektiğinde, zayıf olmak için birini seçin. Seçtiğiniz duruma göre değişir. Bununla ilgili daha fazla bilgi için bu sorunun yanıtlarına bakın .

  • Genel bir kural olarak, delegelerweak çoğu delege sahip olmadıkları sınıflara atıfta bulundukları için işaretlenmelidir . Bir çocuk bir ebeveynle iletişim kurmak için bir delege kullandığında bu kesinlikle doğrudur. Delege için zayıf bir başvuru kullanmak, belgelerin önerdiği şeydir . (Ama bakın bu da.)

  • Protokoller hem referans türleri (sınıflar) hem de değer türleri (yapılar, numaralar) için kullanılabilir. Bu nedenle, bir temsilciyi zayıflatmanız gerektiğinde, onu yalnızca nesne protokolü yapmanız gerekir. Bunu yapmanın yolu AnyObject, protokolün miras listesine eklemektir . (Geçmişte bunu classanahtar kelimeyi kullanarak yaptınız , ancak AnyObjectşimdi tercih edilmektedir .)

    protocol MyClassDelegate: AnyObject {
        // ...
    }
    
    class SomeClass {
        weak var delegate: MyClassDelegate?
    }

İlerideki çalışma

Aşağıdaki makaleleri okumak bunu daha iyi anlamama yardımcı oldu. Ayrıca, unownedanahtar kelime ve kapaklarda meydana gelen güçlü referans döngüleri gibi ilgili konuları da tartışıyorlar .

İlişkili


5
Bütün bunlar güzel ve ilginç, ama aslında asıl sorumla ilgili değil - ne zayıf / ARC'nin kendisi ne de delegelerin genellikle zayıf olduğu ile ilgili değil. Tüm bunları zaten biliyoruz ve zayıf bir protokol referansını nasıl bildirebileceğinizi merak ettik (@flainez tarafından mükemmel bir şekilde cevaplandı).
hnh

30
Haklısın. Aslında daha önce seninle aynı soruyu sordum, ancak bu arka plan bilgilerinin çoğunu kaçırıyordum. Yukarıdaki okumayı yaptım ve sorunuzla ilgili tüm sorunları anlamama yardımcı olacak ek notlar yaptım. Şimdi kabul ettiğin cevabı uygulayabildiğimi ve neden yaptığımı bildiğimi düşünüyorum. Umarım gelecekteki izleyicilere de yardımcı olacaktır.
16'da Suragch

5
Ama tipine bağlı DEĞİL zayıf bir protokol olabilir? Bir protokol kendi kendine hangi nesnenin kendisine uygun olduğunu umursamıyor. Böylece hem bir sınıf, hem de bir yapı ona uygun olabilir. Her ikisine de uyum sağlama avantajına sahip olmak mümkün mü, ancak sadece uygun sınıf tiplerinin zayıf olması mı?
FlowUI. SimpleUITesting.com

> Çoğu delege sahip olmadıkları sınıflara atıfta bulunduğundan, bunu yeniden yazacağım: çoğu delege. Aksi takdirde sahibi olmayan nesne sahibi olur
Victor Jalencas

36

AnyObject Swift'te zayıf bir referans kullanmanın resmi yoludur.

class MyClass {
    weak var delegate: MyClassDelegate?
}

protocol MyClassDelegate: AnyObject {
}

Apple'dan:

Güçlü referans döngülerini önlemek için delegelerin zayıf referanslar olarak beyan edilmesi gerekir. Zayıf başvurular hakkında daha fazla bilgi için, bkz. Sınıf Örnekleri Arasında Güçlü Referans Çevrimleri. Protokolü yalnızca sınıf olarak işaretlemek, daha sonra temsilcinin zayıf bir başvuru kullanması gerektiğini bildirmenize olanak tanır. Yalnızca Sınıf Protokolleri'nde açıklandığı gibi AnyObject öğesinden devralınarak bir protokolü yalnızca sınıf olarak işaretlersiniz .

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID276


7
İlginç. classSwift 4.1'de kullanımdan kaldırıldı mı ?
hnh

@hnh Yine de bir sınıf yaparak bir "sözde protokol" yapabilirsiniz, ancak protokol: AnyObject OP'nin istediği şeyi sınıf yapmaktan daha az yan etkiyle tam olarak yapar. (bu tür bir protokolü değer türleriyle birlikte kullanamazsınız, ancak bunu bir sınıf olarak bildirmek de çözmeyecektir)
Arru

8

Güncelleme: Görünüşe göre kılavuz güncellendi ve bahsettiğim örnek kaldırıldı. Yukarıdaki @ flainez cevabının düzenlemesine bakınız.

Orijinal: Obob-C ile birlikte çalışmasanız bile @objc kullanmak doğru yöntemdir. Protokolünüzün bir numaraya veya yapıya değil, bir sınıfa uygulanmasını sağlar. Kılavuzdaki "Protokol Uygunluğunu Kontrol Etme" konusuna bakın.


Belirtildiği gibi bu IMO sorunun cevabı değildir. Sade bir Swift programı NS'ism'e bağlı olmadan kendi başına durabilmelidir (delege artık değil, başka bir tasarım yapısını da içerebilir). Saf Swift MyClass'ım aslında hedefin bir yapı mı yoksa nesne mi olduğu umurumda değil, opsiyonellere de ihtiyacım yok. Belki daha sonra düzeltirler, sonuçta yeni bir dil. Referans anlambilimi gerekiyorsa, muhtemelen 'sınıf protokolü XYZ' gibi bir şey?
hnh

4
Ben de \ @objc ek yan etkileri olduğunu belirtmek gerekir - @eXhausted NSObjectProtocol önerisi biraz daha iyidir. \ @Objc ile - sınıf temsilcisi 'handleResult (r: MySwiftResultClass)' gibi bir nesne bağımsız değişkeni alırsa, MySwiftResultClass'ın artık NSObject'ten miras alması gerekir! Ve muhtemelen, artık ad alanı değil, vb. Kısaca: \ @objc, bir dil değil, bir köprü oluşturma özelliğidir.
hnh

Bence bunu çözdüler. Şimdi yazıyorsunuz: protokol MyClassDelegate: sınıf {}
user3675131

Bununla ilgili belgeler nerede? Ya
körüm

OP'nin sorusunu cevaplayıp yanıtlamadığından emin değilim, ancak bu özellikle Objc-C ile birlikte çalışıyorsanız yararlıdır;)
Dan Rosenstark

-1

protokol AnyObject sınıfının alt sınıfı olmalıdır

aşağıda verilen örnek

    protocol NameOfProtocol: class {
   // member of protocol
    }
   class ClassName: UIViewController {
      weak var delegate: NameOfProtocol? 
    }

-9

Apple, "sınıf" yerine "NSObjectProtocol" kullanır.

public protocol UIScrollViewDelegate : NSObjectProtocol {
   ...
}

Bu benim için de işe yarar ve kendi temsilci kalıbımı uygulamaya çalışırken gördüğüm hataları sildim.


5
Soru ile ilgili olmayan bu soru, bir temsilci nesnesini destekleyen saf bir Swift sınıfı (özellikle NSObject yok ) oluşturmakla ilgilidir. Bu, yaptığınız şey olan Objective-C protokollerini uygulamakla ilgili değildir. İkincisi @objc aka NSObjectProtocol gerektirir.
hnh

Tamam, ama tavsiye edilmez.
DawnSong
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.