Why can't I use "self.init(type: .custom)" in convenience initializer at my subclass of UIButton

1.8k views Asked by At

I know must call a designated initializer of the superclass, I think init(type: UIButtonType) had called a designated initializer, so I used it in subclass convenience initializer, but failed

class TSContourButton: UIButton {
enum ContourButtonSizeType {
    case large
    case small
}

convenience init(type:ContourButtonSizeType) {
    self.init(type: .custom)
}

then, I tried this. It compiles okay. but, It doesn't look professional

class TSClass: UIButton {

convenience init(frame: CGRect, myString: String) {
    self.init(frame: frame)
    self.init(type: .custom)
}

so, I doubt that I may think wrong. So, I did some test. It successfully called super convenience initializer. Why I can't use self.init(type: .custom) in convenience initializer at my subclass of UIButton?

class person: UIButton {
var name: String = "test"

override init(frame: CGRect) {
    super.init(frame: .zero)
    self.name = "one"
}

convenience init(myName: String) {
    self.init(frame: .zero)
}

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

}

class man: person {
convenience init(mySex: Int) { // it successfully call superclass convenience initializer
    self.init(myName: "info")
}
2

There are 2 answers

0
Matt On

If, for say, name is your mandatory field, you implement all your initial set up in a function. And you should handle if name is not available. I'll keep small as the default option if no type was provided.

// MARK:- Designated Initializers
required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)

    initialSetup(type: .small)
}

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

    initialSetup(type: .small)
}

// MARK:- Convenience Initializers
convenience init(type: ContourButtonSizeType) {
    self.init(frame: .zero)

    initialSetup(type: type)
}

func initialSetup(type: ContourButtonSizeType) {
    // handle all initial setup 
}
0
GorCat On

init(type: UIButtonType) is not UIButton's designated initializer, init(frame: CGRect) is the right designated initializer of UIButton

you just need to overwrite init(frame: CGRect)

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let button1 = MyButton(type: .custom)
    }

}

class MyButton: UIButton {

    // 初始化父类的指定构造器,然后你就可以获得父类的便利构造器
    // overwrite the designated initializer of the super class, then you can automatically inherit the convenience initializer of the super class
    override init(frame: CGRect) {
        super.init(frame: frame)
    }

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

if you want to customize your own button, you can add convenience init(myType: UIButton.ButtonType)

    class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let button1 = MyButton(type: .custom)
        let button2 = MyButton(myType: .custom)
    }

}


class MyButton: UIButton {

    // 初始化父类的指定构造器,然后你就可以获得父类的便利构造器
    // overwrite the designated initializer of the super class, then you can automatically inherit the convenience initializer of the super class
    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    // 创建自己的遍历构造器
    // this is what you want
    convenience init(myType: UIButton.ButtonType) {
        self.init(type: myType) // called the convenience initializer which you automatically inherit from super class
        // customize your own button
    }

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

If this is useful to you, can you give me a like, (づ ̄ 3 ̄)づ