2017-05-11 2 views
2

NSCoding에는 init(coder:)이 필요하지만이 방법의 선택적 버전이 init?(coder:)입니다.init의 선택도 (코더 :) 대 init (코더 :). nil 일 경우 어떻게해야합니까?

nil을 반환하면 정확히 무엇을해야합니까? 이것도 문제입니까?

init(coder:)으로 개체의 큰 계층을 초기화하고 각 개체의 자식 개체 자체를 init?(coder:)을 사용하여 초기화한다고 가정 해보십시오. 어딘가에있는 객체 중 하나가 nil 인 경우 앱이 다운되지 않습니까? 부모 개체가 무아을 기대하지 않습니다.

"초기화하지 않으려면"무엇을 의미합니까?

class Parent: NSCoding { 

     var children: [Child] 

     required init?(coder aDecoder: NSCoder) { 
      guard let children = aDecoder.decodeObject(forKey: "children") as? [Child] else { return nil } 
      self.children = children 
     } 

    } 

    class Child: NSCoding { 
     var name: String 

     required init?(coder aDecoder: NSCoder) { 
      guard let name = aDecoder.decodeObject(forKey: "name") as? String else { return nil } 
      self.name = name 
     } 

    } 

한 가지 전략은 단순히 단순히 nil을 반환하지 않고 새 인스턴스를 반환하는 것입니다. 데이터가 손실되지만 앱이 실행됩니다.

+2

(그러나 예상은 1 개 요소 배열입니다) nil'. 이 경우에는 '가드'가 필요하지 않습니다. – vadian

+1

만약 그것이 nil이 아니어야한다면'self.name = aDecoder.decodeObject (forKey : "name")처럼! 문자열'. 충돌을 일으키지 않으려면 기본값 인'self.name = aDecoder.decodeObject (forKey : "name")를 기본값으로 초기화하는 것이 좋습니다. 문자열 ?? "". – xiangxin

답변

1

nil을 보내지 않는 것이 좋습니다.

Xcode 8.3.2 (8E2002)의 테스트에서 init(coder:)nil을 반환하면 NSKeyedUnarchiver.unarchiveObject이 다운되거나 예기치 않은 결과가 반환됩니다.

"TEST2"에 대한 잘못된 데이터 유형을 인코딩 클래스 준비 :

class MyClass: NSObject, NSCoding { 
    var x: String 

    init(_ x: String) { 
     self.x = x 
    } 

    required init?(coder aDecoder: NSCoder) { 
     guard let x = aDecoder.decodeObject(forKey: "x") as? String else { 
      return nil 
     } 
     self.x = x 
    } 

    func encode(with aCoder: NSCoder) { 
     if x == "test2" { 
      aCoder.encode(Int(4), forKey: "x") 
     } else { 
      aCoder.encode(x, forKey: "x") 
     } 
    } 
} 

TestCaseA : 다음 보관 취소, MyClass 이상이 포함 된 사전을 보관합니다.

결과 : NSKeyedUnarchiver.unarchiveObject에서 충돌이 발생합니다.

let encodedData = NSKeyedArchiver.archivedData(withRootObject: [ 
     "k1":MyClass("test1"), 
     "k2":MyClass("test2"), 
     "k3":"normal things" 
     ]) 
    UserDefaults.standard.set(encodedData, forKey: "xx") 


    if let data = UserDefaults.standard.data(forKey: "xx"), 
     let _data = NSKeyedUnarchiver.unarchiveObject(with: data) { 
     if let dict = _data as? [String:Any] { 
      debugPrint(dict.count) 
     } 
    } 

TestCaseB는 : 상기 MyClass 후 보관 해제 포함하는 배열을 보관.

결과 : 빈 배열을 반환 당신이 경우 * 인코딩 ~ 만이 아닌 선택의 건물 인 * 디코딩 *`init` 방법은`반환 할 수 없습니다

let encodedData = NSKeyedArchiver.archivedData(withRootObject: [ 
     MyClass("test1"), 
     MyClass("test2") 
     ]) 
    UserDefaults.standard.set(encodedData, forKey: "xx") 


    if let data = UserDefaults.standard.data(forKey: "xx"), 
     let _data = NSKeyedUnarchiver.unarchiveObject(with: data) { 
     if let dict = _data as? [Any] { 
      debugPrint(dict.count) 
     } 
    } 
+0

이 기사가 훌륭한 점이 될 것이라고 생각합니다. http://www.jessesquires.com/swift-failable-initializers-revisited/. init에서 nil을 돌려 보내서는 안되며 사전에 일종의 사전 검증을해야합니다. – MH175