Swift에서 실패 가능한 초기화를 구현하는 모범 사례
다음 코드를 사용하여 간단한 모델 클래스를 정의하려고 하는데 실패 가능한 이니셜라이저로 (json-) 사전을 매개 변수로 사용합니다.가야다를 반환해야 .nil
사용자 이름이 원래 json에 정의되지 않은 경우.
1. 왜 코드가 컴파일되지 않습니까?오류 메시지에 다음과 같이 표시됩니다.
클래스 인스턴스의 저장된 모든 속성은 초기화기에서 0을 반환하기 전에 초기화되어야 합니다.
그것은 말이 안됩니다.데왜한을야까?까야io할을nyneid데ln한왜 snil
?
2. 제 접근 방식이 옳은 것인가요, 아니면 제 목표를 달성하기 위한 다른 아이디어나 공통적인 패턴이 있을까요?
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()
}
}
그것은 말이 안됩니다.0을 반환할 계획인데 왜 이러한 속성을 초기화해야 합니까?
Chris Lattner에 따르면 이것은 벌레입니다.그의 말은 이렇습니다.
이는 릴리스 노트에 문서화된 swift 1.1 컴파일러의 구현 제한 사항입니다.컴파일러는 현재 모든 경우에 부분적으로 초기화된 클래스를 파괴할 수 없기 때문에 필요한 상황의 형성을 허용하지 않습니다.우리는 이것을 기능이 아닌 향후 출시될 버그로 생각합니다.
편집:
swift는 현재 오픈 소스이며 이 변경 로그에 따르면 swift 2.2의 스냅샷으로 수정되었습니다.
failable 또는 switching으로 선언된 지정된 클래스 초기화자는 개체가 완전히 초기화되기 전에 각각 0을 반환하거나 오류를 던질 수 있습니다.
업데이트: Swift 2.2 변경 로그로부터(2016년 3월 21일 출시):
failable 또는 switching으로 선언된 지정된 클래스 초기화자는 개체가 완전히 초기화되기 전에 각각 0을 반환하거나 오류를 던질 수 있습니다.
Swift 2.1 이전 버전의 경우:
Apple의 문서(및 컴파일러 오류)에 따르면 클래스는 반환하기 전에 저장된 모든 속성을 초기화해야 합니다.nil
오류가 발생한 초기화기에서:
그러나 클래스의 경우 해당 클래스에 의해 도입된 모든 저장된 속성이 초기화 값으로 설정되고 초기화 위임이 수행된 후에만 실패 가능한 초기화기가 초기화 실패를 트리거할 수 있습니다.
참고: 실제로 클래스가 아니라 구조와 열거에 대해 잘 작동합니다.
초기화기가 실패하기 전에 초기화할 수 없는 저장된 속성을 처리하는 방법은 암시적으로 포장되지 않은 옵션으로 선언하는 것입니다.
문서의 예:
class Product {
let name: String!
init?(name: String) {
if name.isEmpty { return nil }
self.name = name
}
}
위의 예제에서 Product 클래스의 이름 속성은 암시적으로 랩핑되지 않은 선택적 문자열 유형(String!)으로 정의됩니다.선택적 유형이기 때문에 초기화 중에 이름 속성에 특정 값이 할당되기 전에 기본값이 0임을 의미합니다.이 기본값이 0이면 Product 클래스에서 도입한 모든 속성이 유효한 초기값을 가짐을 의미합니다.결과적으로 제품에 대한 실패 가능한 초기화기는 초기화기 내의 이름 속성에 특정 값을 할당하기 전에 빈 문자열을 전달하면 초기화기 시작 시 초기화 실패를 트리거할 수 있습니다.
하는, 를 입니다.userName
String!
오류는 클래스의 할 때 여전히 . 즉,본의을는에해히다지에기야일는다지s에기euttxer야doelly일히s,gNSObject
운 와 .userName
String!
를 할 수 있습니다.super.init()
return nil
당신의 안에 들어갈 것입니다.NSObject
기본 클래스와 컴파일 오류를 수정합니다.
class User: NSObject {
let userName: String!
let isSuperUser: Bool = false
let someDetails: [String]?
init?(dictionary: NSDictionary) {
super.init()
if let value = dictionary["user_name"] as? String {
self.userName = value
}
else {
return nil
}
if let value: Bool = dictionary["super_user"] as? Bool {
self.isSuperUser = value
}
self.someDetails = dictionary["some_details"] as? Array
}
}
저는 마이크 S의 대답이 애플의 추천인 것은 인정하지만, 최선의 관행은 아니라고 생각합니다.강력한 유형의 시스템의 핵심은 런타임 오류를 컴파일 시간으로 이동시키는 것입니다.이 "해결책"은 그 목적을 달성하지 못합니다.을 IMHO로 이 좋을 것 .""
init.init.init.init.init.init.nit.nit.nit.nit.nit.공백 userNames(사용자 이름)이 허용되는 경우 플래그를 설정합니다.
class User: NSObject {
let userName: String = ""
let isSuperUser: Bool = false
let someDetails: [String]?
init?(dictionary: [String: AnyObject]) {
if let user_name = dictionary["user_name"] as? String {
userName = user_name
}
if let value: Bool = dictionary["super_user"] as? Bool {
isSuperUser = value
}
someDetails = dictionary["some_details"] as? Array
super.init()
if userName.isEmpty {
return nil
}
}
}
이 제한을 피하기 위한 또 다른 방법은 초기화를 수행하기 위해 클래스 함수를 사용하는 것입니다.해당 기능을 확장으로 이동할 수도 있습니다.
class User: NSObject {
let username: String
let isSuperUser: Bool
let someDetails: [String]?
init(userName: String, isSuperUser: Bool, someDetails: [String]?) {
self.userName = userName
self.isSuperUser = isSuperUser
self.someDetails = someDetails
super.init()
}
}
extension User {
class func fromDictionary(dictionary: NSDictionary) -> User? {
if let username: String = dictionary["user_name"] as? String {
let isSuperUser = (dictionary["super_user"] as? Bool) ?? false
let someDetails = dictionary["some_details"] as? [String]
return User(username: username, isSuperUser: isSuperUser, someDetails: someDetails)
}
return nil
}
}
이를 사용하면 다음과 같습니다.
if let user = User.fromDictionary(someDict) {
// Party hard
}
Swift 2.2가 출시되어 초기화기에 오류가 발생하기 전에 개체를 완전히 초기화할 필요는 없지만 https://bugs.swift.org/browse/SR-704 이 수정될 때까지 참고 있어야 합니다.
스위프트 1.2에서 할 수 있다는 것을 알았습니다.
몇 가지 조건이 있습니다.
- 필수 속성은 암시적으로 포장 해제 옵션으로 선언해야 합니다.
- 필요한 속성에 한 번만 값을 할당합니다.이 값은 0일 수 있습니다.
- 클래스가 다른 클래스에서 상속되는 경우 super.init()를 호출합니다.
- 필요한 모든 속성에 값이 할당되었으면 해당 값이 예상대로인지 확인합니다.그렇지 않으면 0으로 반환합니다.
예:
class ClassName: NSObject {
let property: String!
init?(propertyValue: String?) {
self.property = propertyValue
super.init()
if self.property == nil {
return nil
}
}
}
값 유형(즉, 구조 또는 열거형)에 대한 실패 가능한 초기화기는 초기화기 구현 내의 모든 지점에서 초기화 실패를 트리거할 수 있습니다.
그러나 클래스의 경우 해당 클래스에 의해 도입된 모든 저장된 속성이 초기화 값으로 설정되고 초기화 위임이 수행된 후에만 실패 가능한 초기화기가 초기화 실패를 트리거할 수 있습니다.
발췌본: Apple Inc."The Swift Programming Language" 아이북스https://itun.es/sg/jEUH0.l
편리함을 이용할 수 있습니다.
class User: NSObject {
let userName: String
let isSuperUser: Bool = false
let someDetails: [String]?
init(userName: String, isSuperUser: Bool, someDetails: [String]?) {
self.userName = userName
self.isSuperUser = isSuperUser
self.someDetails = someDetails
}
convenience init? (dict: NSDictionary) {
guard let userName = dictionary["user_name"] as? String else { return nil }
guard let isSuperUser = dictionary["super_user"] as? Bool else { return nil }
guard let someDetails = dictionary["some_details"] as? [String] else { return nil }
self.init(userName: userName, isSuperUser: isSuperUser, someDetails: someDetails)
}
}
언급URL : https://stackoverflow.com/questions/26495586/best-practice-to-implement-a-failable-initializer-in-swift
'programing' 카테고리의 다른 글
축소 도구막대 배치를 프로그래밍 방식으로 축소 또는 확장 (0) | 2023.09.09 |
---|---|
안드로이드 1.6: "android.view.WindowManager $BadToken 예외:창을 추가할 수 없습니다. 토큰 null은 응용 프로그램을 위한 것이 아닙니다." (0) | 2023.09.09 |
Oracle: 트리거 실행을 위한 한 열의 업데이트 제외 (0) | 2023.09.09 |
Mysql에도 mssql과 같은 @@ROWCOUNT가 있습니까? (0) | 2023.09.09 |
표의 불일치 - Galera 군집 분석 (0) | 2023.09.09 |