【问题标题】:Build error: Must call a designated initializer of the superclass 'UIControl'构建错误:必须调用超类“UIControl”的指定初始化程序
【发布时间】:2021-11-18 21:18:22
【问题描述】:

我想根据 iOS 版本使用一个或另一个初始化器。如果不是 iOS 14,我想设置 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)
    ^

知道我需要如何调用这个便利初始化程序以便构建它吗?

【问题讨论】:

    标签: swift xcode ios14 uicontrol


    【解决方案1】:

    你的init(action: @escaping () -> Void)是一个指定初始化器,并且指定初始化器不允许从基类调用便利初始化器,它们必须调用另一个指定器初始化器。

    这是强制执行的here:

    规则 1
    指定初始化程序必须从其直接超类调用指定初始化程序。

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

    /// 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 的新子类将强制您的所有自定义类从该子类派生,您可以使用新的便利初始化程序扩展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?()
        }
    }
    

    【讨论】:

    • 谢谢,但关于最后一个,addAction 也仅适用于 iOS 14。
    • @regina_fallangi 对,不知道我是怎么错过的。从问题中删除它,并用另一种替代方法替换它。
    猜你喜欢
    • 2018-05-16
    • 2014-09-29
    • 2016-03-11
    • 2016-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多