Za pomocą poniższego kodu próbuję zdefiniować prostą klasę modelu i jej dostępny inicjalizator, który jako parametr przyjmuje słownik (json-). Inicjator powinien zwrócić, nil
jeśli nazwa użytkownika nie jest zdefiniowana w oryginalnym pliku json.
1. Dlaczego kod się nie kompiluje? Komunikat o błędzie mówi:
Wszystkie przechowywane właściwości wystąpienia klasy muszą zostać zainicjowane przed zwróceniem wartości nil z inicjatora.
To nie ma sensu. Dlaczego powinienem inicjalizować te właściwości, kiedy planuję powrót nil
?
2. Czy moje podejście jest właściwe, czy też byłyby inne pomysły lub wspólne wzorce, aby osiągnąć mój cel?
class User: NSObject {
let userName: String
let isSuperUser: Bool = false
let someDetails: [String]?
init?(dictionary: NSDictionary) {
if let value: String = dictionary["user_name"] as? String {
userName = value
}
else {
return nil
}
if let value: Bool = dictionary["super_user"] as? Bool {
isSuperUser = value
}
someDetails = dictionary["some_details"] as? Array
super.init()
}
}
swift
object-initializers
Kai Huppmann
źródło
źródło
canSetCalculableProperties
parametr boolowski, który umożliwia mojemu inicjatorowi obliczenie właściwości, które można lub nie można utworzyć w locie. Na przykład, jeślidateCreated
brakuje klucza i mogę ustawić właściwość w locie, ponieważcanSetCalculableProperties
parametr ma wartość true, po prostu ustawiam go na bieżącą datę.Odpowiedzi:
Aktualizacja: z dziennika zmian Swift 2.2 (opublikowanego 21 marca 2016 r.):
Dla Swift 2.1 i starszych:
Zgodnie z dokumentacją Apple (i błędem kompilatora), klasa musi zainicjować wszystkie swoje przechowywane właściwości przed powrotem
nil
z dostępnego inicjatora:Uwaga: w rzeczywistości działa dobrze w przypadku struktur i wyliczeń, ale nie klas.
Sugerowanym sposobem obsługi przechowywanych właściwości, których nie można zainicjować przed niepowodzeniem inicjatora, jest zadeklarowanie ich jako niejawnie rozpakowanych opcji.
Przykład z dokumentów:
W twoim przypadku, jednak po prostu definiując
userName
jakoString!
nie naprawić błąd kompilacji, ponieważ wciąż trzeba się martwić o inicjowanie właściwości na swojej klasy bazowejNSObject
. Na szczęście zuserName
definicją aString!
, możesz zadzwonićsuper.init()
przed tobą,return nil
co zainicjuje twojąNSObject
klasę bazową i naprawi błąd kompilacji.źródło
Product
klasy) nie może wywołać błędu inicjalizacji przed przypisaniem określonej wartości, nawet jeśli dokumentacja mówi, że może. Dokumenty nie są zsynchronizowane z najnowszą wersją Swift.var
Zamiast tego zaleca się zrobienie tego na razielet
. źródło: Chris Lattner .Według Chrisa Lattnera jest to błąd. Oto, co mówi:
Źródło
EDYTOWAĆ:
Tak więc Swift jest teraz open source i zgodnie z tym dziennikiem zmian jest teraz naprawiony w migawkach swift 2.2
źródło
Akceptuję, że odpowiedź Mike'a S jest rekomendacją Apple, ale nie sądzę, że jest to najlepsza praktyka. Istotą silnego systemu typów jest przeniesienie błędów uruchomieniowych do czasu kompilacji. To „rozwiązanie” przeczy temu celowi. IMHO, lepiej byłoby przejść dalej i zainicjować nazwę użytkownika,
""
a następnie sprawdzić ją po super.init (). Jeśli puste nazwy użytkowników są dozwolone, ustaw flagę.źródło
Innym sposobem obejścia tego ograniczenia jest praca z funkcjami klas w celu wykonania inicjalizacji. Możesz nawet chcieć przenieść tę funkcję do rozszerzenia:
Używanie go stałoby się:
źródło
Chociaż Swift 2.2 został wydany i nie musisz już w pełni inicjalizować obiektu przed niepowodzeniem inicjalizatora, musisz wstrzymać swoje konie do czasu naprawienia https://bugs.swift.org/browse/SR-704 .
źródło
Dowiedziałem się, że można to zrobić w Swift 1.2
Jest kilka warunków:
Przykład:
źródło
Fragment z: Apple Inc. „ Swift Programming Language. ”IBooks. https://itun.es/sg/jEUH0.l
źródło
Możesz skorzystać z wygody w inicjalizacji :
źródło