NSCoding required initializer in inherited classes in Swift

时间:2015-10-30 22:03:17

标签: ios swift cocoa-touch

I have class Foo which conforms to NSObject and NSCoding which I want to be able to persist with NSKeyedArchiver I want to create class Bar, a subclass of Foo that will also conform to NSObject and NSCoding. I am having a problem understanding how to create the required convenience init?(coder aDecoder: NSCoder) in the subclass.

so class 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)
  }
}

Then class 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)"
  }
}

I can get this to compile by adding the following methods on to make this NSCoding compliant

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

this makes sense because I call super.encodeWithCoder(...) reusing the super makes this DRY. The problem I am having is creating the required convenience init?(...) the only way I can seem to get it to compile is by doing this...

  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)
  }

I basically have copied the superclass required initializer and then added the additional decode method for the subclass property. This approach does not seem correct...

Is there a better way to implement this??

3 个答案:

答案 0 :(得分:0)

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

super.init(coder: aDecoder)

答案 1 :(得分:0)

我在游乐场尝试了你的代码,当我勾选错误的红色圆圈时,它只是自动添加代码。

编码就像你的功能需要方便init。

示例代码:

required convenience init?(coder aDecoder: NSCoder)
{
    fatalError("init(coder:) has not been implemented")
}

答案 2 :(得分:-1)

暂时考虑过这一点,并相信这是实现这一目标的正确方法。

原因是Swift强制执行对象初始化的方式。便捷初始化程序只能在self上调用所需的初始值设定项。只有所需的初始值设定项才能调用init上的super

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

以下是您可以复制到游乐场https://gist.github.com/vorlando/dc29ba98c93eaadbc7b1

的代码
相关问题