Chciałbym przechowywać tablicę słabych referencji w Swift. Sama tablica nie powinna być słabym odniesieniem - jej elementami powinny być. Myślę, że Cocoa NSPointerArray
oferuje nietypową wersję tego.
179
Chciałbym przechowywać tablicę słabych referencji w Swift. Sama tablica nie powinna być słabym odniesieniem - jej elementami powinny być. Myślę, że Cocoa NSPointerArray
oferuje nietypową wersję tego.
Odpowiedzi:
Utwórz ogólne opakowanie jako:
Dodaj wystąpienia tej klasy do swojej tablicy.
Podczas definiowania
Weak
możesz użyć jednego z nichstruct
lubclass
.Ponadto, aby pomóc w zbieraniu zawartości tablicy, możesz zrobić coś w stylu:
Zastosowanie
AnyObject
powyższego powinno zostać zastąpione przezT
- ale nie sądzę, że obecny język Swift zezwala na rozszerzenie zdefiniowane jako takie.źródło
Stuff
protokołem; zobacz to powiązane pytanieMożesz użyć NSHashTable z poorObjectsHashTable.
NSHashTable<ObjectType>.weakObjectsHashTable()
W przypadku Swift 3:
NSHashTable<ObjectType>.weakObjects()
Odwołanie do klasy NSHashTable
źródło
Any
ale nieAnyObject
, takimi jak protokoły.MyProtocol: class
iNSHashTable<MyProtocol>.weakObjects()
. „NSHashTable” wymaga, aby „MyProtocol” był typem klasy.Trochę późno na imprezę, ale spróbuj mojej. Zaimplementowałem jako zestaw, a nie tablicę.
WeakObjectSet
Stosowanie
Uważaj, że WeakObjectSet nie przyjmuje typu String, ale NSString. Ponieważ typ ciągu nie jest AnyType. Moja szybka wersja to
Apple Swift version 2.2 (swiftlang-703.0.18.1 clang-703.0.29)
.Kod można pobrać z Gist. https://gist.github.com/codelynx/30d3c42a833321f17d39
** DODANO W LISTOPADZIE 2017
Zaktualizowałem kod do Swift 4
Jak wspomniał gokeji, doszedłem do wniosku, że NSString nie zostanie zwolniony na podstawie używanego kodu. Porysowałem głowę i napisałem klasę MyString w następujący sposób.
Następnie wymień
NSString
zeMyString
tak. To dziwne, że to działa.Potem znalazłem dziwną stronę, która może być związana z tym problemem.
https://bugs.swift.org/browse/SR-5511
Mówi, że problem jest,
RESOLVED
ale zastanawiam się, czy nadal jest to związane z tym problemem. W każdym razie różnice w zachowaniu między MyString lub NSString wykraczają poza ten kontekst, ale byłbym wdzięczny, gdyby ktoś wymyślił ten problem.źródło
nil
wartości z wewnętrznychSet
. Dodałem więcreap()
funkcję wymienioną w górnej odpowiedzi i upewniłem się, że dzwonię przyreap()
każdymWeakObjectSet
dostępie.nil
NSString
nie działa.UnsafeMutablePointer<T>(&object)
może zmieniać się losowo (tak samo jakwithUnsafePointer
). Teraz używam wersji wspieranej przezNSHashTable
: gist.github.com/simonseyer/cf73e733355501405982042f760d2a7d .To nie jest moje rozwiązanie. Znalazłem to na forach programistów Apple .
@GoZoner ma dobrą odpowiedź, ale powoduje awarię kompilatora Swift.
Oto wersja kontenera o słabych obiektach nie powoduje awarii aktualnie wydanego kompilatora.
Następnie możesz utworzyć tablicę tych kontenerów:
źródło
EXC_BAD_ACCESS
za mnie Z klasą działa dobrzeMożesz to zrobić, tworząc obiekt opakowujący do przechowywania słabego wskaźnika.
A następnie używając ich w tablicy
źródło
class
do użytkuweak
varsprotocol Protocol : class { ... }
Co powiesz na funkcjonalne opakowanie?
Wystarczy zadzwonić do zwrócenia zamknięcia, aby sprawdzić, czy cel nadal żyje.
I możesz przechowywać te zamknięcia w tablicy.
Możesz odzyskać słabo uchwycone wartości, odwzorowując wywołania zamknięć.
W rzeczywistości nie potrzebujesz funkcji do zamknięcia. Wystarczy przechwycić obiekt bezpośrednio.
źródło
var array: [(x: Int, y: () -> T?)]
. Właśnie tego szukałem.let values = Array(array1.map({ $0() })) part
. Ponieważ nie jest to już tablica zamknięć o słabych referencjach, wartości zostaną zachowane do momentu zwolnienia tej tablicy. Jeśli mam rację, ważne jest, aby pamiętać, że nigdy nie powinieneś zachowywać tej tablicy,self.items = Array(array1.map({ $0() }))
ponieważ jest to lepsze niż cel.Miałem ten sam pomysł, aby stworzyć słaby pojemnik z lekami generycznymi.
W rezultacie stworzyłem opakowanie dla
NSHashTable
:Stosowanie:
Nie jest to najlepsze rozwiązanie, ponieważ
WeakSet
można je zainicjować dowolnym typem, a jeśli ten typ nie jest zgodnyAnyObject
protokołem, aplikacja ulegnie awarii ze szczegółowym powodem. Ale obecnie nie widzę lepszego rozwiązania.Pierwotnym rozwiązaniem było zdefiniowanie
WeakSet
w ten sposób:Ale w tym przypadku
WeakSet
nie można zainicjować za pomocą protokołu:Obecnie powyższego kodu nie można skompilować (Swift 2.1, Xcode 7.1).
Dlatego zrezygnowałem z zgodności
AnyObject
i dodałem dodatkowych strażników zfatalError()
zapewnieniami.źródło
Detale
Rozwiązanie
opcja 1
Wykorzystanie opcji 1
Opcja 2
Wykorzystanie opcji 2
Pełna próbka
źródło
protocol TP: class { } class TC { var a = WeakArray<TP>() var b = WeakObjectsArray<TP>() }
protocol TP: class { } class TC<TYPE> where TYPE: TP { var a = WeakObjectsArray<TYPE>() // Use like regular array. With any objects var weakObjectsArray = [TYPE?]() }
delegates
. Wtedy miałbyś pewną liczbę kontrolerów widoku, którzy chcieliby korzystać z tej funkcji. Spodziewałbyś się zadzwonićMyManager.delegates.append(self)
. Ale jeśliMyManager
jest zablokowany na jakimś ogólnym typie, nie jest to zbyt użyteczne.protocol TP: class { } class MyManager { typealias Delegate = AnyObject & TP static var delegates = [Delegate?]() } class A: TP { } class B: TP { } //MyManager.delegates.append(A()) //MyManager.delegates.append(B())
Istniejący przykład WeakContainer jest pomocny, ale tak naprawdę nie pomaga używać słabych referencji w istniejących szybkich kontenerach, takich jak Listy i Słowniki.
Jeśli chcesz używać metod List, takich jak zawiera, WeakContainer będzie musiał zaimplementować Equatable. Dodałem więc kod, aby umożliwić równoważenie WeakContainer.
Na wypadek, gdybyś chciał używać WeakContainer w słownikach, stworzyłem też hashable, dzięki czemu może być używany jako klucze słownika.
Zmieniłem też nazwę na WeakObject, aby podkreślić, że dotyczy to tylko typów klas i odróżnić go od przykładów WeakContainer:
To pozwala ci robić fajne rzeczy, takie jak Słownik słabych referencji:
źródło
Oto jak zrobić @ wielką odpowiedź GoZoner za zgodne
Hashable
, więc może to być indeksowane w Kontener obiektów takich jak:Set
,Dictionary
,Array
, itd.źródło
Ponieważ
NSPointerArray
już obsługuje większość tego automatycznie, rozwiązałem problem, tworząc dla niego bezpieczne opakowanie, które pozwala uniknąć wielu problemów z kotłem w innych odpowiedziach:Przykładowe użycie:
To więcej pracy z góry, ale użycie reszty kodu jest znacznie czystsze IMO. Jeśli chcesz, aby uczynić go bardziej podobny do tablicy, można nawet wdrożyć indeksowanie, sprawiają, że
SequenceType
, itd (ale tylko mój projekt musiappend
iforEach
tak nie mam dokładny kod na rękę).źródło
Jeszcze inne rozwiązanie tego samego problemu ... celem tego jest przechowywanie słabego odniesienia do obiektu, ale także umożliwienie przechowywania struktury.
[Nie jestem pewien, czy jest to przydatne, ale zajęło trochę czasu, aby uzyskać prawidłową składnię]
źródło
Możesz utworzyć opakowanie wokół
Array
. Lub skorzystaj z tej biblioteki https://github.com/NickRybalko/WeakPointerArraylet array = WeakPointerArray<AnyObject>()
Typ jest bezpieczny.źródło
Inne odpowiedzi dotyczyły kąta ogólnego. Pomyślałem, że podzielę się prostym kodem obejmującym
nil
kąt.Chciałem mieć statyczną tablicę (od czasu do czasu odczytywaną) wszystkich
Label
aplikacji istniejących obecnie w aplikacji, ale nie chciałem widziećnil
, gdzie były stare.Nic szczególnego, to mój kod ...
źródło
flatMap
zamiastfilter
&map
?Oparłem to na pracy @Eonil, ponieważ podobała mi się strategia słabego wiązania zamknięcia, ale nie chciałem używać operatora funkcji dla zmiennej, ponieważ wydawało mi się to sprzeczne z intuicją
To, co zrobiłem, to:
W ten sposób możesz zrobić coś takiego jak:
źródło
To moje rozwiązanie:
-
źródło
Jest to bezpieczna kolekcja typu, która przechowuje pojemniki ze słabymi przedmiotami. Automatycznie usuwa również zero pojemników / opakowań po uzyskaniu dostępu.
Przykład:
Kolekcja niestandardowa https://gist.github.com/djk12587/46d85017fb3fad6946046925f36cefdc
źródło
Co z podejściem funkcjonalnym ?
Jest to główny pomysł, a następnie dodaj dowolną logikę wygody, aby śledzić zawartość tablicy. Na przykład, można rozważyć to samo podejście ze słownikiem wykorzystującym klucz jako sposób na znalezienie tego, co jest w środku.
źródło