UIKit init error?

When i run the main app, print 0 ?????
The child init failed.
It passed build.

i create a Module 1 framework, the main app use it.
Something wrong.

Module 1:

import UIKit

public protocol Initializable {
    init()
}
extension UIView: Initializable {}

open class ParentView: UIView {
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    required public init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Main APP:

import UIKit
import Parent

public class ChildView: ParentView {
    let a = 10
    
    func run() {
        print(a)
    }
}

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        
        let child = ChildView()
        let b = child.a
        print(b)
        
        return true
    }

}

Test Code

Thank you, that's really worrying example.

Here's a version of your code that doesn't involve modules:

import UIKit

struct S: CustomStringConvertible {
    var inited = false
    init() {
        inited = true
        print("S.init")
    }
    var description: String {
        precondition(inited)
        return "S description, inited: \(inited)"
    }
}

class Parent: UIView {
    private // comment / uncomment this line
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    required public init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

class Child: Parent {
    let a = S()
}

func test() {
    let c = Child()
    print(c.a)
}

@main class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        test()
        return true
    }
}

with the line "comment / uncomment this line" commented out (so the initialiser is not private) everything works OK. with this line left as is (so the initialiser is private) the code still compiles ok - but generates some bogus code: the code where "S" variable initialiser could be bypassed – this is clearly wrong.

There's some dodginess in how UIKit "init" operates under the hood. This is likely to do with obj-c <-> swift interop and how when you call .init() it automatically calls "init(frame: .zero)" under the hood (perhaps in some extension)? If you have enough time and motivation you may create another minimal example that replicates this bug without using UIKit / UIViews, would be interesting to know if you can replicate it without involving obj-c or if obj-c is the necessary ingredient here.

PS. your original example could be fixed by making "override init(frame: CGRect)" public (or just remove both initialisers from Parent class (and remove the funny initializable business). I believe it is the same issue as in the version that doesn't use modules.

1 Like