Podczas sesji WWDC 2014 403 Intermediate Swift i transkrypcji pojawił się następujący slajd
Mówca powiedział w takim przypadku, że jeśli go nie użyjemy [unowned self]
, nastąpi wyciek pamięci. Czy to oznacza, że zawsze powinniśmy używać [unowned self]
zamknięcia wewnętrznego?
W linii 64 ViewController.swift aplikacji Swift Weather nie używam [unowned self]
. Ale aktualizuję interfejs za pomocą niektórych @IBOutlet
takich jak self.temperature
i self.loadingIndicator
. Może być OK, ponieważ wszystkie @IBOutlet
s, które zdefiniowałem, są weak
. Ale czy ze względów bezpieczeństwa powinniśmy zawsze używać [unowned self]
?
class TempNotifier {
var onChange: (Int) -> Void = {_ in }
var currentTemp = 72
init() {
onChange = { [unowned self] temp in
self.currentTemp = temp
}
}
}
swift
automatic-ref-counting
Jake Lin
źródło
źródło
onChange
powinien być[weak self]
zamknięciem, ponieważ jest to właściwość publiczna (wewnętrznie, ale nadal), aby inny obiekt mógł uzyskać i przechowywać zamknięcie, utrzymując obiekt TempNotifier w pobliżu (bezterminowo, jeśli obiekt używający nie puściłonChange
zamknięcia, dopóki nie zobaczy, żeTempNotifier
zniknął, poprzez swoje własne słabe odniesienie doTempNotifier
) . Gdybyvar onChange …
były,private var onChange …
to[unowned self]
byłoby poprawne. Nie jestem jednak tego w 100% pewien; proszę mnie poprawić, jeśli się mylę.[]
? Nie mogę znaleźć wyjaśnienia w dokumentach Apple.{}
to puste zamknięcie (instancja zamknięcia) jako domyślne (nic nie robi),(Int) -> Void
to definicja zamknięcia.Odpowiedzi:
Nie, zdecydowanie są chwile, w których nie chciałbyś korzystać
[unowned self]
. Czasami chcesz, aby zamknięcie uchwyciło siebie, aby upewnić się, że jest jeszcze w pobliżu, zanim zostanie wywołane zamknięcie.Przykład: wykonywanie asynchronicznego żądania sieciowego
Jeśli dokonujesz asynchroniczne żądanie sieciowe Ci zrobić chcą zamknięcie zachować
self
uwagę przy zakończeniu zgłoszeń. W przeciwnym razie obiekt ten mógł zostać zwolniony, ale nadal chcesz być w stanie obsłużyć zakończenie żądania.Kiedy stosować
unowned self
lubweak self
Jedynym momentem, w którym naprawdę chcesz użyć
[unowned self]
lub[weak self]
jest moment, w którym stworzyłbyś silny cykl odniesienia . Silny cykl odniesienia występuje wtedy, gdy istnieje pętla własności, w której obiekty ostatecznie posiadają siebie nawzajem (być może za pośrednictwem strony trzeciej) i dlatego nigdy nie zostaną zwolnione, ponieważ oba zapewniają wzajemne trzymanie się.W konkretnym przypadku zamknięcia wystarczy uświadomić sobie, że każda zmienna, do której się odwołuje, jest „własnością” tego zamknięcia. Tak długo, jak zamknięcie jest w pobliżu, obiekty te są gwarantowane w pobliżu. Jedynym sposobem na zatrzymanie tej własności jest zrobienie
[unowned self]
lub[weak self]
. Więc jeśli klasa jest właścicielem zamknięcia, a to zamknięcie zawiera silne odniesienie do tej klasy, wówczas istnieje silny cykl odniesienia między zamknięciem a klasą. Obejmuje to również, jeśli klasa posiada coś, co jest właścicielem zamknięcia.W szczególności w przykładzie z wideo
W przykładzie na slajdzie
TempNotifier
jest właścicielem zamknięcia poprzezonChange
zmienną elementu. Gdyby nie zadeklarowaliself
jakounowned
, zamknięcie również byłoby równoznaczne zself
utworzeniem silnego cyklu odniesienia.Różnica między
unowned
iweak
Różnica między
unowned
iweak
jestweak
zadeklarowana jako Opcjonalna, podczas gdyunowned
nie jest. Deklarując to,weak
możesz zająć się sprawą, że w pewnym momencie może ona być zerowa. Jeśli spróbujesz uzyskać dostęp dounowned
zmiennej, która jest zerowa, spowoduje to awarię całego programu. Dlatego używaj tylkounowned
wtedy, gdy jesteś pozytywny, że zmienna będzie zawsze w pobliżu, gdy zamknięcie jest w pobliżuźródło
[weak self]
w asynchronicznym żądaniu sieci jest kontroler widoku, w którym to żądanie jest używane do wypełnienia widoku. Jeśli użytkownik się wycofuje, nie musimy już wypełniać widoku ani nie potrzebujemy odwołania do kontrolera widoku.weak
odniesienia są również ustawione,nil
gdy obiekt jest zwalniany.unowned
odniesienia nie są.unowned
jest używany donon-Optional
kiedyweak
jest używany,Optional
więc naszself
jestOptional
czynon-optional
?Aktualizacja 11/2016
Napisałem artykuł na ten temat, rozszerzając tę odpowiedź (patrząc na SIL, aby zrozumieć, co robi ARC), sprawdź to tutaj .
Oryginalna odpowiedź
Poprzednie odpowiedzi tak naprawdę nie zawierają prostych zasad określających, kiedy należy używać jednego nad drugim i dlaczego, więc dodam kilka rzeczy.
Nieznana lub słaba dyskusja sprowadza się do pytania o czas życia zmiennej i odnoszące się do niej zamknięcie.
Scenariusze
Możesz mieć dwa możliwe scenariusze:
Zamknięcie ma taki sam okres istnienia zmiennej, więc zamknięcie będzie osiągalne tylko do momentu osiągnięcia zmiennej . Zmienna i zamknięcie mają taki sam okres użytkowania. W takim przypadku powinieneś zadeklarować odwołanie jako nienależące do właściciela . Typowym przykładem jest
[unowned self]
używany w wielu przykładach małych zamknięć, które robią coś w kontekście swojego rodzica i które nie są przywoływane nigdzie indziej, nie przeżywają swoich rodziców.Czas życia zamknięcia jest niezależny od jednego ze zmiennej, zamknięcie może być nadal przywoływane, gdy zmienna nie jest już osiągalna. W takim przypadku powinieneś zadeklarować referencję jako słabą i sprawdzić, czy nie jest zerowa przed użyciem (nie wymuszaj rozpakowywania). Typowym przykładem tego jest to,
[weak delegate]
że można zobaczyć w niektórych przykładach zamknięcia odnoszących się do całkowicie niezwiązanego (w ciągu całego życia) obiektu delegowanego.Rzeczywiste użycie
A więc, które / które powinieneś używać przez większość czasu?
Cytując Joe Groffa z Twittera :
Więcej informacji na temat nieposiadanych
*
wewnętrznych mechanizmów znajdziesz tutaj .*
Zwykle określane również jako nieposiadane (bezpieczne), aby wskazać, że kontrole środowiska wykonawczego (które prowadzą do awarii z powodu nieprawidłowych referencji) są przeprowadzane przed uzyskaniem dostępu do nieznanych referencji.źródło
Pomyślałem, że dodam kilka konkretnych przykładów specjalnie dla kontrolera widoku. Wiele wyjaśnień, nie tylko tutaj na temat Przepełnienia stosu, jest naprawdę dobrych, ale pracuję lepiej z przykładami ze świata rzeczywistego (@drewag miał dobry początek na tym):
weak
, ponieważ są one długie. Kontroler widoku może zamknąć się przed zakończeniem żądania, więcself
nie będzie już wskazywał na prawidłowy obiekt po wywołaniu zamknięcia.Jeśli masz zamknięcie, które obsługuje zdarzenie na przycisku. Może to być
unowned
spowodowane tym, że gdy tylko kontroler widoku zniknie, przycisk i wszelkie inne elementy, do których może się odnosić,self
znikają w tym samym czasie. Blok zamknięcia również zniknie w tym samym czasie.źródło
weak
a nieunowned
prawda?Jeśli jaźń może być zerowa w zamknięciu, użyj [słabego ja] .
Jeśli ja nigdy nie będzie zerowe w zamknięciu, użyj [jaźni nieposiadanej] .
Dokumentacja Apple Swift ma świetną sekcję ze zdjęciami wyjaśniającymi różnicę między używaniem silnych , słabych i nieposiadanych w zamknięciach:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html
źródło
Oto genialne cytaty z forów programistów Apple opisujące pyszne szczegóły:
unowned
vsunowned(safe)
vsunowned(unsafe)
unowned
vsweak
Aktualizacja: we współczesnym Swift
weak
wewnętrznie używa tego samego mechanizmu, counowned
robi . To porównanie jest niepoprawne, ponieważ porównuje Objective-Cweak
z Swiftunonwed
.Powody
Podekscytowany?
źródło
Jest tu kilka świetnych odpowiedzi. Ale ostatnie zmiany w sposobie, w jaki Swift implementuje słabe referencje, powinny zmienić słabe ja każdego użytkownika w porównaniu do niezasłużonych decyzji o własnym użytkowaniu. Poprzednio, jeśli potrzebowałeś najlepszej wydajności, używając jaźni nieposiadanej, był lepszy od słabego ja, tak długo, jak możesz być pewien, że jaźń nigdy nie będzie zerowa, ponieważ dostęp do jaźni nieposiadanej jest znacznie szybszy niż dostęp do jaźni słabej.
Ale Mike Ash udokumentował, w jaki sposób Swift zaktualizował implementację słabych zmiennych, aby używał tabel bocznych i jak to znacznie poprawia słabą samoocenę.
https://mikeash.com/pyblog/friday-qa-2017-09-22-swift-4-weak-references.html
Teraz, gdy nie ma znacznego ograniczenia wydajności dla słabego ja, uważam, że powinniśmy domyślnie używać go dalej. Zaletą słabego ja jest to, że jest opcjonalny, co znacznie ułatwia pisanie bardziej poprawnego kodu, jest to w zasadzie powód, dla którego Swift jest tak świetnym językiem. Może ci się wydawać, że wiesz, które sytuacje są bezpieczne dla korzystania z nieposiadanego siebie, ale moje doświadczenie z przeglądaniem wielu innych kodów programistów jest takie, że większość tego nie robi. Naprawiłem wiele awarii, w wyniku których nieprzydzielone ja zostało cofnięte, zwykle w sytuacjach, gdy wątek w tle kończy się po zwolnieniu kontrolera.
Błędy i awarie są najbardziej czasochłonnymi, bolesnymi i kosztownymi częściami programowania. Staraj się pisać poprawny kod i unikaj ich. Zalecam, aby regułą było, aby nigdy nie wymuszać rozpakowywania opcji i nigdy nie używać jaźni nieposiadanej zamiast słabej jaźni. Nie stracisz niczego, co zmarnuje czas, kiedy wymuszanie rozpakowywania i nieposiadane ja faktycznie są bezpieczne. Ale wiele zyskasz na eliminowaniu trudnych do znalezienia i debugowania awarii i błędów.
źródło
weak
nie można go użyć zamiastunowned
?Według Apple-doc
Przykład -
źródło
Jeśli żadne z powyższych nie ma sensu:
tl; dr
Wyjaśnienie:
Pobrałem następujące informacje pod adresem: słaby nieposiadany link . Z tego, co zebrałem, nieposiadane ja nie może być zerowe, ale słabe ja może być, a nieposiadane ja może prowadzić do zwisających wskazówek ... czegoś niesławnego w Celu C. Mam nadzieję, że to pomoże
Nieznane referencje, podobnie jak słabe referencje, nie zwiększają liczby zatrzymań obiektu , do którego następuje odwołanie . Jednak w Swift nieznane odwołanie ma tę dodatkową zaletę, że nie jest Opcjonalne . To sprawia, że łatwiej nimi zarządzać niż korzystać z opcjonalnego wiązania. Podobnie jest w przypadku opcji niejawnie nieopakowanych. Ponadto nieposiadane odniesienia nie są zerowane . Oznacza to, że gdy obiekt zostaje zwolniony, nie zeruje wskaźnika. Oznacza to, że użycie nieznanych referencji może w niektórych przypadkach prowadzić do zwisających wskaźników. Dla was kujony, które pamiętają dni Celu C, tak jak ja, nieposiadane referencje odwzorowują niebezpieczne.
Tu zaczyna się trochę mylić.
Oba można wykorzystać do przerwania cykli zatrzymania. Więc kiedy ich używamy ?!
Według dokumentów Apple :
źródło
źródło