weak
odniesienia wydają się nie działać w Swift, chyba że a protocol
jest zadeklarowane jako @objc
, czego nie chcę w czystej aplikacji Swift.
Ten kod podaje błąd kompilacji ( weak
nie można go zastosować do typu nieklasowego MyClassDelegate
):
class MyClass {
weak var delegate: MyClassDelegate?
}
protocol MyClassDelegate {
}
Muszę prefiksować protokół @objc
, a następnie działa.
Pytanie: Jaki jest „czysty” Szybki sposób na osiągnięcie weak
delegate
?
Odpowiedzi:
Musisz zadeklarować typ protokołu jako
AnyObject
.Używając
AnyObject
powiesz, że tylko klasy mogą być zgodne z tym protokołem, podczas gdy struktury lub wyliczenia nie.źródło
protocol ProtocolNameDelegate: AnyObject
, ale nie ma znaczenia.AnyObject
ponieważclass
w pewnym momencie będzie przestarzałe.Dodatkowa odpowiedź
Zawsze byłem zdezorientowany, czy delegaci powinni być słabi, czy nie. Niedawno dowiedziałem się więcej o delegatach i kiedy używać słabych referencji, dlatego dodam tutaj kilka dodatkowych punktów ze względu na przyszłych widzów.
Celem użycia
weak
słowa kluczowego jest uniknięcie silnych cykli odniesienia (zachowanie cykli). Silne cykle odniesienia mają miejsce, gdy dwie instancje klasy mają silne odniesienia do siebie. Ich liczba referencyjna nigdy nie spada do zera, więc nigdy nie zostają zwolnione.Musisz użyć tylko,
weak
jeśli delegat jest klasą. Szybkie struktury i wyliczenia są typami wartości (ich wartości są kopiowane podczas tworzenia nowej instancji), a nie typami referencyjnymi, więc nie tworzą silnych cykli referencyjnych .weak
referencje są zawsze opcjonalne (w przeciwnym razie byś użyłunowned
) i zawsze używająvar
(nielet
), aby opcjonalne można było ustawić,nil
gdy zostanie zwolnione.Klasa nadrzędna powinna oczywiście mieć silne odniesienie do swoich klas podrzędnych, a zatem nie powinna używać
weak
słowa kluczowego. Gdy dziecko chce mieć odniesienie do swojego rodzica, powinno uczynić je słabym odniesieniem za pomocąweak
słowa kluczowego.weak
powinien być używany, gdy chcesz odwołać się do klasy, której nie jesteś właścicielem, nie tylko dla dziecka odwołującego się do jego rodzica. Gdy dwie niehierarchiczne klasy muszą się nawzajem odnosić, wybierz jedną, która ma być słaba. Ten, który wybierzesz, zależy od sytuacji. Więcej informacji na ten temat znajdziesz w odpowiedziach na to pytanie .Zasadniczo delegaci powinni być oznaczeni jako,
weak
ponieważ większość delegatów odwołuje się do klas, których nie są właścicielami. Jest to z pewnością prawda, gdy dziecko używa delegata do komunikowania się z rodzicem. Dokumentacja zaleca stosowanie słabego odniesienia dla delegata . (Ale też to zobacz .)Protokoły mogą być używane zarówno dla typów referencyjnych (klas), jak i typów wartości (struktur, wyliczeń). Dlatego w prawdopodobnym przypadku, gdy musisz osłabić delegata, musisz uczynić go protokołem tylko obiektowym. Można to zrobić poprzez dodanie
AnyObject
do listy dziedziczenia protokołu. (W przeszłości robiłeś to za pomocąclass
słowa kluczowego, aleAnyObject
teraz jest to preferowane ).Dalsze badanie
Czytanie poniższych artykułów pomogło mi zrozumieć to znacznie lepiej. Omawiają również powiązane kwestie, takie jak
unowned
słowo kluczowe i silne cykle odniesienia, które mają miejsce przy zamknięciach.Związane z
źródło
AnyObject
jest oficjalnym sposobem na użycie słabej referencji w Swift.Z Apple:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID276
źródło
class
przestarzałe w Swift 4.1?Aktualizacja: wygląda na to, że instrukcja została zaktualizowana, a przykład, o którym mówiłem, został usunięty. Zobacz zmianę w odpowiedzi na @ flainez powyżej.
Oryginał: Korzystanie z @objc to właściwy sposób, nawet jeśli nie współpracujesz z Obj-C. Zapewnia, że twój protokół jest stosowany do klasy, a nie do wyliczenia lub struktury. Zobacz „Sprawdzanie zgodności protokołu” w podręczniku.
źródło
protokół musi być podklasą AnyObject, klasa
przykład podany poniżej
źródło
Apple używa „NSObjectProtocol” zamiast „class”.
Działa to również dla mnie i usunąłem błędy, które widziałem podczas próby wdrożenia własnego wzorca delegowania.
źródło