NSCoding 在 Swift 的继承类中需要初始化器

Posted

技术标签:

【中文标题】NSCoding 在 Swift 的继承类中需要初始化器【英文标题】:NSCoding required initializer in inherited classes in Swift 【发布时间】:2015-10-30 22:03:17 【问题描述】:

我有符合 NSObjectNSCoding 的类 Foo 我希望能够坚持使用 NSKeyedArchiver 我想创建类 Bar,它是 Foo 的子类,它也将符合 NSObject 和 @ 987654325@。我在理解如何在子类中创建 required convenience init?(coder aDecoder: NSCoder) 时遇到问题。

所以类Foo...

class Foo: NSObject, NSCoding 
  let identifier:String
  init(identifier:String) 
    self.identifier = identifier
  

  override var description:String 
    return "Foo: \(identifier)"
  

  func encodeWithCoder(aCoder: NSCoder) 
    aCoder.encodeObject(identifier, forKey: "identifier")
  

  required convenience init?(coder aDecoder: NSCoder) 
    guard let identifier = aDecoder.decodeObjectForKey("identifier") as? String
      else 
        return nil
    
    self.init(identifier:identifier)
  

然后类 Bar ...

class Bar:Foo 
  let tag:String

  init(identifier:String, tag:String) 
    self.tag = tag
    super.init(identifier: identifier)
  

  override var description:String 
    return "Bar: \(identifier) is \(tag)"
  

我可以通过添加以下方法来编译它以使其符合 NSCoding 兼容

  override func encodeWithCoder(aCoder: NSCoder) 
    aCoder.encodeObject(tag, forKey: "tag")
    super.encodeWithCoder(aCoder)
  

这是有道理的,因为我调用super.encodeWithCoder(...) 重用超级使这个干燥。我遇到的问题是创建required convenience init?(...) 我似乎可以编译它的唯一方法是这样做......

  required convenience init?(coder aDecoder:NSCoder) 
    guard let identifier = aDecoder.decodeObjectForKey("identifier") as? String,
          let tag        = aDecoder.decodeObjectForKey("tag") as? String
      else 
        return nil
    

    self.init(identifier:identifier, tag:tag)
  

我基本上已经复制了超类所需的初始化程序,然后为子类属性添加了额外的解码方法。这种方法似乎不正确...

有没有更好的方法来实现这个?

【问题讨论】:

super.init(coder: aDecoder) 【参考方案1】:

在所需的 init 方法中解码并分配所有子类属性后,立即调用:

super.init(coder: aDecoder)

【讨论】:

不完全确定您要将呼叫添加到super.init(coder:aDecoder) 的位置,请提供更多详细信息.. 谢谢 here is a link to an example【参考方案2】:

已经考虑了一段时间,并相信这是实现这一点的正确方法。

原因在于 Swift 强制对象初始化的方式。便利初始化器只能在self 上调用所需的初始化器。只有所需的初始化程序才能在super 上调用init

因此,初始化子类对象的唯一方法是在调用子类所需初始化程序之前解码所有必需的初始化参数...然后调用超类初始化程序

这是您可以复制到游乐场https://gist.github.com/vorlando/dc29ba98c93eaadbc7b1的代码

【讨论】:

您好,请给我的答案打分的人提供解释...谢谢【参考方案3】:

我在 Playground 中尝试过您的代码,当我勾选错误的红色圆圈时,它只是自动添加代码。

编码就像你的函数需要方便初始化。

示例代码:

required convenience init?(coder aDecoder: NSCoder)

    fatalError("init(coder:) has not been implemented")

【讨论】:

这解决了为编译程序而需要初始化程序的问题。仍然需要实现便利初始化程序,否则当您尝试解码存档对象时,您将生成fatalErrorNSKeyedUnarchiver.unarchiveObjectWithFile(_:)

以上是关于NSCoding 在 Swift 的继承类中需要初始化器的主要内容,如果未能解决你的问题,请参考以下文章

Swift 中 SKProduct 的 NSCoding 错误

Swift,NSCoding 保存类的数组不起作用

如何在 Swift 的 NSCoding 初始化中返回预先存在的核心数据对象?

使用 NSCoding Swift 保存对象时出现异常

如何让我的简单对象符合 Swift 中的 NSManagedObject 和 NSCoding

Swift 的 NSCoding 中的 EXC_BAD_INSTRUCTION