Build error: Must call a designated initializer of the superclass 'UIControl'

Build error: Must call a designated initializer of the superclass 'UIControl'

我想根据 iOS 版本使用一个初始化器或另一个。如果不是iOS14,我想设置action以后使用。我对超级构造函数的调用发生在 if/else:

class Control: UIControl {

    var action: (() -> Void)?

    init(action: @escaping () -> Void) {
        self.action = action
        if #available(iOS 14.0, *) {
            let primaryAction = UIAction(handler: { _ in action() })
            super.init(frame: .zero, primaryAction: primaryAction)
        } else {
            super.init(frame: .zero)
        }
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}

来电是:

let controlThatDoesNotWork = Control(action: { print("this doesn not work") })

构建错误是

error: must call a designated initializer of the superclass 'UIControl'
    super.init(frame: .zero, primaryAction: primaryAction)
    ^

知道我需要如何调用这个便捷初始化器来构建它吗?

你的 init(action: @escaping () -> Void) 是指定构造器,指定构造器不允许从基础 class 调用便利构造器,它们必须调用另一个指定构造器。

这是强制执行的 here:

Rule 1
    A designated initializer must call a designated initializer from its immediate superclass.

这是讨论中的基本初始化程序:

/// Initializes the control and adds primaryAction for the UIControlEventPrimaryActionTriggered control event. Subclasses of UIControl may alter or add behaviors around the usage of primaryAction, see subclass documentation of this initializer for additional information.
@available(iOS 14.0, *)
public convenience init(frame: CGRect, primaryAction: UIAction?)

因此,您需要将您的初始化器转换为方便的初始化器,并且必须使用 self 而不是 super 调用其他初始化器(同样,由于初始化器规则):

class Control: UIControl {

    var action: (() -> Void)?

    convenience init(action: @escaping () -> Void) {
        if #available(iOS 14.0, *) {
            let primaryAction = UIAction(handler: { _ in action() })
            self.init(frame: .zero, primaryAction: primaryAction)
        } else {
            self.init(frame: .zero)
        }
        self.action = action
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    } 
}

或者,添加 UIControl 的新子 class 将强制所有自定义 class 派生自该子 class,您可以扩展 UIControl一个新的便利初始值设定项:

extension UIControl {
    // associated object dance to allow "stored" properties
    // in extensions and protocols over NSObject subclasses
    private static var primaryActionKey: UInt8 = 0
    private var primaryAction: (() -> Void)? {
        get {
            objc_getAssociatedObject(self, &Self.primaryActionKey) as? () -> Void
        }
        set {
            objc_setAssociatedObject(self, &Self.primaryActionKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    convenience init(action: @escaping () -> Void) {
        if #available(iOS 14.0, *) {
            let primaryAction = UIAction(handler: { _ in action() })
            self.init(frame: .zero, primaryAction: primaryAction)
        } else {
            self.init(frame: .zero)
            self.primaryAction = action
            addTarget(self, action: #selector(onPrimaryAction), for: .primaryActionTriggered)
        }
    }
    
    @objc private func onPrimaryAction() {
        primaryAction?()
    }
}