programowanieProgramista iOS

Jak działają inicjalizatory failable (`init?`) w Swift? Kiedy i dlaczego je stosować, jakie ważne niuanse należy uwzględnić?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

Failable inicjalizatory (init?) w Swift pozwalają opisać sytuację, gdy utworzenie instancji typu może zakończyć się niepowodzeniem i zwrócić nil. Często używa się ich do walidacji danych wejściowych lub konwersji, które mogą nie zakończyć się sukcesem. W failable inicjalizatorze można jawnie zwrócić nil, wskazując na nieudane utworzenie obiektu.

Przykład:

struct User { let name: String let age: Int init?(name: String, age: Int) { guard !name.isEmpty, age > 0 else { return nil } self.name = name self.age = age } }

Dzięki temu można zapobiegać tworzeniu nieprawidłowych obiektów.

Ważne niuanse:

  • W łańcuchu dziedziczenia failable inicjalizatory mogą być nadpisywane tylko przez inne failable inicjalizatory.
  • Przy użyciu struktury z failable inicjalizatorem w tablicy, gdzie odbywa się mapowanie inicjalizacji (compactMap), jest to wygodne do filtrowania nieprawidłowych instancji.

Pytanie podchwytliwe

Pytanie: Czym różni się init? od init! i kiedy używać failable inicjalizatora z implicit unwrapping?

Odpowiedź: init? zwraca opcjonal (<type?>), a jeżeli inicjalizacja się nie powiodła, zwróci nil, co wymaga bezpiecznego przetwarzania. init! zwraca implicitly unwrapped optional (<type!>), a jeżeli inicjalizacja się nie powiodła, również zwróci nil, ale użycie takiego obiektu bez sprawdzenia spowoduje runtime-crash. Używaj init! tylko wtedy, gdy masz pewność, że inicjalizacja nie może zakończyć się niepowodzeniem w Twoim kontekście (na przykład podczas pracy z storyboardem w UIKit).

let value = Int("abc") // value będzie nil

Przykłady rzeczywistych błędów spowodowanych nieznajomością niuansów tematu.


Historia

Podczas ręcznego parsowania JSON użyto zwykłego inicjalizatora zamiast failable. Doprowadziło to do stworzenia "pustych" użytkowników, ponieważ walidacja nie zadziałała i aplikacja nie filtrowała nieprawidłowych danych.


Historia

Użycie init! z potencjalnie nieprawidłowymi danymi doprowadziło do awarii aplikacji po aktualizacji API: format danych wejściowych uległ zmianie, a w momencie wydobywania obiektu wystąpił wyjątek runtime z powodu niejawnego rozpakowywania nil.


Historia

Przy własnej implementacji failable init zapomniano jawnie zwrócić nil dla niektórych scenariuszy, co w efekcie doprowadziło do zainicjowania struktury z "brudnymi" polami, co później spowodowało błędy w logice biznesowej.