1

My app crashes when I try to access a property of a Codable subclass instance and if one of the two conditions are met:

  1. The subclass is a multilevel child of Codable
  2. There is a function that calls JSONEncoder().encode That function doesn't have to be called, it only needs to be present where you instantiated the class in question.

Entity.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: (initial view controller)

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

}

There are several things that I'm confused about:

  • Just having a function that calls JSONEncoder().encode causes the crash. Even if that function isn't called anywhere.

  • If you put let _: Data? = try? JSONEncoder().encode(childEntity) right after the initialization of ChildEntity, the app will not crash, even if you let the causesCorruptionEvenIfNotCalled function that I just talked about above.

  • If ChildEntity inherits directly from Codable, then there's no issues, the app doesn't crash.

How can I prevent the crash while keeping the inheritance structure and the function with the JSON encoder?

Here is an example project: https://drive.google.com/open?id=1mrhOmm4kOAdMjLk5nlFLDeo6vTsBo1Uv

rayan
  • 49
  • 4

1 Answers1

0

It seems inheriting from Codable conforming class is somehow not completely supported out of the box. I had to override func encode(to encoder: Encoder) throws and call super inside. I assumed that was the default behaviour but I was wrong.

The ChildEntity class now look like this:

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

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

From the Swift core code, it does not call super: https://github.com/apple/swift/blob/master/stdlib/public/core/Codable.swift.gyb

This bug seems somewhat related: https://bugs.swift.org/browse/SR-4772

rayan
  • 49
  • 4