Swift ma składnię deklaracji właściwości bardzo podobną do C #:
var foo: Int {
get { return getFoo() }
set { setFoo(newValue) }
}
Ma jednak willSet
i didSet
działania. Są one wywoływane odpowiednio przed i po wywołaniu settera. Jaki jest ich cel, biorąc pod uwagę, że możesz mieć ten sam kod w seterie?
swift
callback
didset
property-observer
skradać się
źródło
źródło
get
&set
) polega zasadniczo na obliczeniu właściwości na podstawie innej właściwości, np. Konwersji etykiettext
na rokInt
.didSet
iwillSet
czy możemy powiedzieć ... hej, ta wartość została ustawiona, teraz zróbmy to, np. Nasze źródło danych zostało zaktualizowane ... więc przeładujmy tableView, aby zawierał nowe wiersze. Aby zobaczyć inny przykład, zobacz odpowiedź dfri na temat dzwonienia do delegatówdidSet
Odpowiedzi:
Chodzi o to, że czasami potrzebujesz właściwości, która ma automatyczne przechowywanie i pewne zachowanie, na przykład, aby powiadomić inne obiekty, że właściwość właśnie się zmieniła. Gdy wszystko, co masz, to
get
/set
, potrzebujesz innego pola do przechowywania wartości. Za pomocąwillSet
ididSet
możesz podejmować działania, gdy wartość jest modyfikowana bez potrzeby używania innego pola. Na przykład w tym przykładzie:myProperty
wypisuje swoją starą i nową wartość przy każdej modyfikacji. Z tylko getterami i setterami potrzebowałbym tego zamiast tego:Więc
willSet
ididSet
reprezentują ekonomię kilku liniach, i mniej hałasu w liście pól.źródło
willSet
ididSet
nie są wywoływane, gdy ustawia się właściwość z metody init, jak zauważa Apple:willSet and didSet observers are not called when a property is first initialized. They are only called when the property’s value is set outside of an initialization context.
myArrayProperty.removeAtIndex(myIndex)
... Nie oczekiwane.Rozumiem, że set i get są dla obliczonych właściwości (brak kopii zapasowej z przechowywanych właściwości )
jeśli pochodzisz z Celu-C, pamiętaj, że zmieniły się konwencje nazewnictwa. W Swift zmienna iVar lub zmienna instancji nosi nazwę właściwości przechowywanej
Przykład 1 (właściwość tylko do odczytu) - z ostrzeżeniem:
Powoduje to ostrzeżenie, ponieważ powoduje rekurencyjne wywołanie funkcji (sam getter wywołuje sam). Ostrzeżenie w tym przypadku to „Próba zmodyfikowania„ testu ”we własnym getterze”.
Przykład 2. Warunkowy odczyt / zapis - z ostrzeżeniem
Podobny problem - nie możesz tego zrobić, ponieważ rekurencyjnie wywołuje setera. Pamiętaj też, że ten kod nie będzie narzekał na brak inicjatorów, ponieważ nie ma przechowywanej właściwości do inicjalizacji .
Przykład 3. odczyt / zapis obliczonej właściwości - z zapleczem
Oto wzorzec, który umożliwia warunkowe ustawienie rzeczywistej przechowywanej właściwości
Uwaga Rzeczywiste dane nazywa się _test (chociaż mogą to być dowolne dane lub kombinacja danych). Należy również zwrócić uwagę na potrzebę podania wartości początkowej (alternatywnie musisz użyć metody init), ponieważ _test jest w rzeczywistości zmienną instancji
Przykład 4. Korzystanie z will i did set
Widzimy tutaj willSet i didSet przechwytujące zmianę w rzeczywistej przechowywanej właściwości. Jest to przydatne do wysyłania powiadomień, synchronizacji itp. (Patrz przykład poniżej)
Przykład 5. Konkretny przykład - Kontener ViewController
Zwróć uwagę na użycie OBA obliczonych i przechowywanych właściwości. Użyłem obliczonej właściwości, aby zapobiec dwukrotnemu ustawianiu tej samej wartości (aby uniknąć złych rzeczy!); Użyłem willSet i didSet do przekazywania powiadomień do viewControllers (zobacz dokumentację UIViewController i informacje o kontenerach viewController)
Mam nadzieję, że to pomoże, i proszę, niech ktoś krzyknie, jeśli popełniłem błąd tutaj!
źródło
//I can't see a way to 'stop' the value being set to the same controller - hence the computed property
ostrzeżenie zniknie po tym, jak użyłemif let newViewController = _childVC {
zamiastif (_childVC) {
get
myślę, że musisz dodać,if _childVC == nil { _childVC = something }
a następniereturn _childVC
.Są to tak zwani obserwatorzy właściwości :
Fragment: Apple Inc. „Swift Programming Language”. iBooks. https://itun.es/ca/jEUH0.l
Podejrzewam, że pozwala to na rzeczy, które tradycyjnie robimy z KVO, takie jak wiązanie danych z elementami interfejsu użytkownika lub wywoływanie skutków ubocznych zmiany właściwości, uruchamiania procesu synchronizacji, przetwarzania w tle itp.
źródło
źródło
Możesz także użyć,
didSet
aby ustawić zmienną na inną wartość. Nie powoduje to ponownego wezwania obserwatora, jak podano w Przewodniku po właściwościach . Na przykład przydaje się, gdy chcesz ograniczyć wartość, jak poniżej:źródło
Wiele dobrze napisanych istniejących odpowiedzi dobrze obejmuje pytanie, ale wspomnę bardziej szczegółowo o dodatku, który moim zdaniem jest wart omówienia.
Te
willSet
ididSet
własności obserwatorzy mogą być używane do wywołania delegatów, na przykład, dla właściwości klasy, które są zawsze tylko zaktualizowane przez interakcji użytkownika, ale gdzie chcesz uniknąć wywołanie delegata przy inicjalizacji obiektu.Przytoczę podniesiony komentarz Klaasa do zaakceptowanej odpowiedzi:
Jest to dość schludne, ponieważ oznacza, że np.
didSet
Właściwość jest dobrym wyborem punktu uruchamiania dla wywołań zwrotnych i funkcji delegowanych dla własnych klas niestandardowych.Jako przykład rozważmy niestandardowy obiekt kontroli użytkownika z pewną kluczową właściwością
value
(np. Pozycja w kontroli oceny), zaimplementowany jako podklasaUIView
:Po czym funkcje delegowane mogą być używane, powiedzmy, w niektórych kontrolerach widoków do obserwowania kluczowych zmian w modelu
CustomViewController
, podobnie jak w przypadku korzystania z nieodłącznych funkcji delegowania obiektówUITextFieldDelegate
forUITextField
(nptextFieldDidEndEditing(...)
.).W tym prostym przykładzie użyj wywołania zwrotnego delegowanego z
didSet
właściwości class,value
aby poinformować kontroler widoku, że jedno z jego gniazd ma powiązaną aktualizację modelu:Tutaj
value
właściwość została enkapsulowana, ale ogólnie: w takich sytuacjach uważaj, aby nie aktualizowaćvalue
właściwościcustomUserControl
obiektu w zakresie powiązanej funkcji delegowania (tutajdidChangeValue()
:) w kontrolerze widoku, w przeciwnym razie skończysz na nieskończona rekurencja.źródło
Zauważ, że
willSet
potrzebna jest nazwa parametru do obejścia, z drugiej stronydidSet
nie.źródło
Getter i setter są czasami zbyt ciężkie, aby je wdrożyć, aby zaobserwować właściwe zmiany wartości. Zwykle wymaga to dodatkowej obsługi zmiennych tymczasowych i dodatkowych kontroli, a ty będziesz unikać nawet tych drobnych robocizny, jeśli napiszesz setki pobierających i ustawiających. Te rzeczy są odpowiednie do sytuacji.
źródło
willSet
didSet
We własnej (podstawowej) klasie
willSet
ididSet
są one dość redundantne , ponieważ zamiast tego można zdefiniować obliczoną właściwość (tj. Metody get- i set-), która uzyskuje dostęp_propertyVariable
do żądanej operacji poprzedzającej i postprocesowej .Jeżeli jednak , by zastąpić klasę, w którym nieruchomość jest już zdefiniowany , następnie
willSet
ididSet
są użyteczne i nie zbędny!źródło
Jedną z rzeczy, która
didSet
jest naprawdę przydatna, jest użycie gniazdek w celu dodania dodatkowej konfiguracji.źródło
Nie znam C #, ale przy odrobinie zgadywania myślę, że rozumiem co
robi. Wygląda bardzo podobnie do tego, co masz w Swift, ale to nie to samo: w Swift nie masz
getFoo
isetFoo
. To nie jest mała różnica: oznacza, że nie masz żadnego bazowego miejsca na swoją wartość.Swift ma zapisane i obliczone właściwości.
Obliczona właściwość ma
get
i może miećset
(jeśli jest zapisywalna). Ale kod w module pobierającym i ustawiającym, jeśli muszą faktycznie przechowywać niektóre dane, muszą to zrobić w innych właściwościach. Nie ma miejsca na kopię zapasową.Z drugiej strony przechowywana właściwość ma pamięć zapasową. Ale nie ma
get
iset
. Zamiast tego mawillSet
i za pomocądidSet
którego można obserwować zmiany zmiennych i ostatecznie wywoływać skutki uboczne i / lub modyfikować zapisaną wartość. Nie maszwillSet
ididSet
dla obliczonych właściwości i nie potrzebujesz ich, ponieważ dla obliczonych właściwości możesz użyć koduset
do kontrolowania zmian.źródło
getFoo
isetFoo
są prostymi symbolami zastępczymi dla wszystkiego, co chcesz, aby robiły i ustawiające. C # też ich nie potrzebuje. (Zrobiłem przegap kilka składniowe subtelności jak poprosiłem wcześniej miałem dostęp do kompilatora.)