初始化需要`init(coder:NSCoder)`

时间:2019-01-14 21:23:07

标签: swift cocoa nscoding

我想继承CAShapeLayer的子类,因此它将保存对数据模型中相应对象的引用:

class CPCoursePointLayer : CAShapeLayer
{
    let itsDataRef :CPCoursePoint
    let itsEventData :CPEventData

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    init( coursePoint: CPCoursePoint, in eventData :CPEventData)
    {
        itsDataRef = coursePoint
        itsEventData = eventData
    }
}

其中itsDataRefitsEventData是对基础数据的引用(如果需要,可以指向指针)。这样,如果我移动了may图层类的实例,或者使用eventData中指定的图形样式来绘制模型,则可以更新模型。我的CPCoursePointLayer不拥有这些变量,无法使用Rust术语。

现在我需要实现一个init(coder:)初始化程序,如何从零开始初始化实例变量?我可以从NSCoder解码“指针”吗?对我来说这没有意义...

尽管我永远不会打电话给init(coder:),但我想我在那里,因为系统可能会调用它。然后,我将有一个无法使用的实例...

如果我将实例变量声明为可选(?),我想避免在每个方法中执行额外的if let带来的额外负担。

2 个答案:

答案 0 :(得分:1)

如果不想在子类中支持NSCoding,则典型的解决方案是在fatalError中使用init(coder:)。实际上,如果您完全省略了初始化程序,编译器甚至会提供它作为修复程序:

fix-it

所以只要这样做:

class CPCoursePointLayer: CAShapeLayer {
    let itsDataRef: CPCoursePoint
    let itsEventData: CPEventData

    init(coursePoint: CPCoursePoint, in eventData: CPEventData) {
        itsDataRef = coursePoint
        itsEventData = eventData
        super.init()
    }

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

}

系统通常不会尝试解码自定义图层的实例。

答案 1 :(得分:0)

您基本上有三个选择:

  1. 将变量声明为隐式展开的可选变量
  2. init?(coder:)是否失败,无论是否致命
  3. 已通过CPCoursePoint实现CPEventDatainit?(coder:)的取消归档

选项1:

class CPCoursePointLayer : CAShapeLayer
{
    let itsDataRef :CPCoursePoint!
    let itsEventData :CPEventData!

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    init( coursePoint: CPCoursePoint, in eventData :CPEventData)
    {
        itsDataRef = coursePoint
        itsEventData = eventData
    }
}

如果您引用itsDataRefitsEventData并且对象没有被新的初始化程序初始化,则会导致崩溃。

选项2(a)

class CPCoursePointLayer : CAShapeLayer
{
    let itsDataRef :CPCoursePoint
    let itsEventData :CPEventData

    required init?(coder aDecoder: NSCoder) {
        return nil
    }

    init( coursePoint: CPCoursePoint, in eventData :CPEventData)
    {
        itsDataRef = coursePoint
        itsEventData = eventData
    }
}

如果使用init(coder:),这将只会初始化对象。

选项2(b)

class CPCoursePointLayer : CAShapeLayer
{
    let itsDataRef :CPCoursePoint
    let itsEventData :CPEventData

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) is not supported for this class"
    }

    init( coursePoint: CPCoursePoint, in eventData :CPEventData)
    {
        itsDataRef = coursePoint
        itsEventData = eventData
    }
}

如果调用init(coder:),这将导致程序崩溃。

选项3

class CPCoursePointLayer : CAShapeLayer
{
    let itsDataRef :CPCoursePoint
    let itsEventData :CPEventData

    required init?(coder aDecoder: NSCoder) {
        guard let itsDataRef = aDecoder.decodeObject(forKey:"itsDataRef"),
              let itsEventData = aDecoder.decodeObject(forKey:"itsEventData") else {
            return nil
        }
        self.itsDataRef = itsDataRef
        self.itsEventData = itsEventData
        super.init(coder: aDecoder)
    }

    init( coursePoint: CPCoursePoint, in eventData :CPEventData)
    {
        itsDataRef = coursePoint
        itsEventData = eventData
    }
}

选项2(b)可能是最常见的,因为它是“快速失败”的-如果调用该初始化程序,则应该在测试过程中迅速捕获到这一点。