【问题标题】:Initialize subclass that requires `init(coder: NSCoder)`初始化需要 `init(coder: NSCoder)` 的子类
【发布时间】:2019-01-14 21:23:06
【问题描述】:

我想继承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 是对基础数据的引用(如果您愿意,可以使用指针)。这样,如果我移动了可能层类的实例,或者使用eventData 中指定的图形样式绘制它,我就可以更新模型。我的CPCoursePointLayer拥有这些变量,使用 Rust 术语。

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

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

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

【问题讨论】:

  • 您可以实现该方法并让它抛出一个致命错误,因为您不会使用它。

标签: swift cocoa nscoding


【解决方案1】:

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

那就这样做吧:

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

}

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

【讨论】:

    【解决方案2】:

    你基本上有三个选择:

    1. 将变量声明为隐式展开的选项
    2. init?(coder:) 失败,无论是否致命
    3. CPCoursePointCPEventData 通过init?(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) 可能是最常见的,因为它是“快速失败” - 如果调用了该初始化程序,您应该在测试期间很快发现这一点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-11-22
      • 2014-12-07
      • 1970-01-01
      • 1970-01-01
      • 2023-04-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多