【问题标题】:`supportsSecureCoding` crashes when using Optimize for Speed option使用优化速度选项时,`supportsSecureCoding` 崩溃
【发布时间】:2018-09-27 20:12:41
【问题描述】:

我在创建使用 NSSecureCoding 及其子类的类时遇到问题。

class ClassA: NSObject, NSSecureCoding {
    public static var supportsSecureCoding: Bool { return true }
}

class ClassB: ClassA {
    public static var supportsSecureCoding: Bool { return true } // "Cannot override static var"
}

我应该这样称呼它,因为 NSObject.h 中的文档说,

此属性必须在所有允许安全编码的类上返回 YES。采用 NSSecureCoding 并覆盖 initWithCoder: 的类的子类也必须覆盖此方法并返回 YES。 // 编写解码数据的方法时应参考安全编码指南。

目标-C:

@property (class, readonly) BOOL supportsSecureCoding;

斯威夫特:

public static var supportsSecureCoding: Bool { get }

我使用的是 Xcode 10.0,在 Swift 4.0 和 Swift 4.2 上都试过了。 人们如何解决这个问题?任何帮助表示赞赏。

更新: 使用 public class var supportsSecureCoding 时,它会编译,但在使用 Optimize for Speed 时会在运行时崩溃。

【问题讨论】:

    标签: swift nssecurecoding


    【解决方案1】:

    当它的定义与其超类相同时,似乎 Swift 的当前优化器会抑制生成覆盖的 getter 方法。多么聪明的优化器!?

    这种 hack 会抑制这种过于强烈的优化。

    class ClassB: ClassA {
    
        //...
    
        static private var secureCoding = true
        override public class var supportsSecureCoding: Bool { return secureCoding }
    
    }
    

    static private let 没有相同的效果。因此,当 Swift 优化器更加聪明时,上面的代码可能无法正常工作。最好尽快发送错误报告。


    似乎 Swift 优化器已经足够聪明了,上面的解决方法可能不起作用。 (参见 Martin R 的评论。)

    您可能需要删除private。

    class ClassB: ClassA {
    
        //...
    
        static var secureCoding = true
        override public class var supportsSecureCoding: Bool { return secureCoding }
    
    }
    

    【讨论】:

    • 我同意它看起来像一个错误。但即使使用您的解决方法,如果优化它仍然会崩溃。这是我快速而肮脏的测试代码:gist.github.com/martinr448/03aa3f425a636d469769020dbe3953b5.
    • @MartinR,谢谢,我在一个 iOS 项目中测试了我的代码,但对于一个小项目来说,优化器似乎已经足够聪明了。也许你需要删除private。
    • 确实,它可以工作(在 macOS 命令行项目中)!
    • 有趣的变种:override public class var supportsSecureCoding: Bool { return Int.random(in: 1...1) > 0 }
    • @OOPer @MartinR Using static private var secureCoding = true 仍然崩溃,但 static var secureCoding = true 使它工作。谢谢!多么奇怪的编译器错误:D
    【解决方案2】:

    类声明中的static 是final class 的别名,即类型方法 它不能在子类中被覆盖。你想要的是一个class 方法

    public class var supportsSecureCoding: Bool { return true }
    

    可以在子类中用

    覆盖
    override public class var supportsSecureCoding: Bool { return true }
    

    【讨论】:

    • 您可能还需要添加 @objc 以将方法公开给 Objective-C 运行时。
    • 感谢您的回复。我试过这个,但我在运行时崩溃(因此我开始研究这个问题)```***由于未捕获的异常'NSInvalidUnarchiveOperationException'而终止应用程序,原因:'类'MyModel'有一个支持安全编码的超类,但 'MyModel' 会覆盖 -initWithCoder: 并且不会覆盖 +supportsSecureCoding。该类必须实现 +supportsSecureCoding 并返回 YES 以验证它的 -initWithCoder: 实现是否符合安全编码。'`` 在子类中,我确实有 @objc override public class var supportsSecureCoding: Bool { return true }
    • @Gomfucius:它适用于我的简单测试。您能否发布一个导致崩溃的最小独立示例?
    • 您可以尝试将 Swift 优化级别设置为“优化速度”并再试一次吗?我认为这是造成问题的原因。
    • @Gomfucius:是的,这里也是。 – 它在 Debug 配置中工作,但在 Release 配置中崩溃。不幸的是,我不知道为什么会这样。
    【解决方案3】:

    对我有用的修复

    private static var secureCodingWorkaround = true
    @objc override public class var supportsSecureCoding: Bool { return secureCodingWorkaround }
    

    【讨论】:

      【解决方案4】:

      我无法获得上述任何答案。这绝对是苹果方面的一个错误,他们需要解决,因此请确保将其发送到反馈系统中。我什至没有运气就添加了@objc。

      Swift 5.3 编译器现在为未指定安全编码的初始化提供 NSKeyedArchiver 的弃用消息。但显然该语言不允许在子类中覆盖它。

      当我不覆盖我得到的变量时: 错误:“子类”类有一个支持安全编码的超类,但“子类”覆盖了 -initWithCoder:并且不覆盖 +supportsSecureCoding。该类必须实现 +supportsSecureCoding 并返回 YES 以验证其 -initWithCoder: 的实现是否符合安全编码。 (NSInvalidUnarchiveOperationException)

      当我覆盖变量时,我得到:“不能覆盖静态变量”

      有条件的解决方法:

      这个解决方法对我有用,因为我有一个超类型,它有点抽象,因为它永远不会在没有子类型的情况下使用。如果您有类似的设置,这应该适合您:

      public class Supertype: NSObject, NSCoding {
           ...
      
      }
      

      子类型:

      public class SubType: Supertype, NSSecureCoding {
      
           public static var supportsSecureCoding = true
           ...
      }
      

      这样 var 至少存在于我使用的所有子类型中。

      如果您直接实例化并使用 Supertype,这将不适合您。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-03
        • 1970-01-01
        • 2012-07-10
        • 2011-08-01
        相关资源
        最近更新 更多