1

当我尝试访问Codable子类实例的属性并且满足以下两个条件之一时,我的应用程序崩溃:

  1. 子类是一个多级子类Codable
  2. 有一个调用JSONEncoder().encode该函数的函数不必调用,它只需要出现在您实例化相关类的位置即可。

实体.swift:

class Entity: Codable {

}

ChildEntity.swift:

// If ChildEntity inherits from Entity, the app will crash
/* If ChildEntity simply implements Codable like so : class ChildEntity: Codable,
    the app will not crash even with the 'causesCorruptionEvenIfNotCalled' function in ChildEntityController
*/
class ChildEntity: Entity {
    var name: String = ""
}

ViewController.swift:(初始视图控制器)

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let childEntity: ChildEntity = ChildEntity()

        // Simply having the function 'causesCorruptionEvenIfNotCalled' in the code  (not calling it) causes 'childEntity' properties to become inacessible

        // Before accessing the property, 'childEntity.name' is a normal empty String

        let name: String = childEntity.name // CRASH: name cannot be accessed because of a EXC_BAD_ACCESS error

        // At this point 'childEntity.name' is corrupted with random data but 'name' has an empty String
        // You can get get the property's value but inspecting either 'name' and 'childEntity.name' throws and EXC_BAD_ACCESS error

        print("name: \(name)")
    }

    // Commenting or removing this function's body will prevent all the issues below
    func causesCorruptionEvenIfNotCalled(object: Entity) {
        let _: Data? = try? JSONEncoder().encode(object)
    }

}

有几件事我很困惑:

  • 只是有一个调用的函数JSONEncoder().encode会导致崩溃。即使没有在任何地方调用该函数。

  • 如果你let _: Data? = try? JSONEncoder().encode(childEntity)在初始化之后立即放ChildEntity,应用程序不会崩溃,即使你让causesCorruptionEvenIfNotCalled我刚才说的功能。

  • 如果ChildEntity直接继承自Codable,则没有问题,应用程序不会崩溃。

如何在使用 JSON 编码器保持继承结构和功能的同时防止崩溃?

这是一个示例项目:https ://drive.google.com/open?id=1mrhOmm4kOAdMjLk5nlFLDeo6vTsBo1Uv

4

1 回答 1

0

Codable开箱即用似乎不完全支持从符合类继承。我不得不在func encode(to encoder: Encoder) throws里面覆盖并调用超级。我认为这是默认行为,但我错了。

类现在ChildEntity看起来像这样:

class ChildEntity: Entity {
    var name: String = ""

    override func encode(to encoder: Encoder) throws {
        try super.encode(to: encoder)
    }
}

从 Swift 核心代码来看,它并没有调用 super:https ://github.com/apple/swift/blob/master/stdlib/public/core/Codable.swift.gyb

这个错误似乎有点相关:https ://bugs.swift.org/browse/SR-4772

于 2018-08-01T10:01:31.977 回答