如何初始化 UIButton 子类?

我试图在 Swift 中为 UIButton 的子类添加一个双值。我尝试了所有的 inits 和 get 和 set 选项,但是我不能让它工作。

所以我从这个开始:

class CVSTButton : UIButton {
var cvstPosition: Double


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


super.init(coder: aDecoder)
}
}

然后我试着:

class CVSTButton : UIButton {
var cvstPosition: Double {
get {
return self.cvstPosition
}
set {
self.cvstPosition = newValue
}


}


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

怎么了?

58719 次浏览

You need two things there -- (1) cvstPosition needs an initial value, either in the declaration or in the init before you call super.init(). (2) That call to fatalError is put in so you don't forget to implement the initializer -- it’s basically an on-purpose crash. Delete!

Setting the initial value in the declaration, there isn’t any need for an init:

class CVSTButton : UIButton {
var cvstPosition: Double = 0
}

Or setting the initial value in the initializer:

class CVSTButton : UIButton {
var cvstPosition: Double


required init(coder aDecoder: NSCoder) {
cvstPosition = 0


super.init(coder: aDecoder)
}
}

Swift >= 2.2:

Since this version subclassing the UIButton, makes your button to have .custom type.

Swift 2:

convenience init(type buttonType: UIButtonType) {
super.init(frame: CGRectZero)


// this button be automatically .Custom
}

Swift:

override class func buttonWithType(buttonType: UIButtonType) -> AnyObject {
let button = super.buttonWithType(buttonType) as! UIButton
// your default code
return button
}

With Swift 3, according to your needs, you may choose one of the seven following code snippets to solve your problem.


1. Create your UIButton subclass with a custom initializer

This solution allows you to create instances of your UIButton subclass with the appropriate value for your property. With this solution, you can only create instances of your UIButton subclass programmatically.

import UIKit


class CustomButton: UIButton {


var myValue: Int


required init(value: Int = 0) {
// set myValue before super.init is called
self.myValue = value


super.init(frame: .zero)


// set other operations after super.init, if required
backgroundColor = .red
}


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


}

Usage:

import UIKit


class ViewController: UIViewController {


override func viewDidLoad() {
super.viewDidLoad()


let button = CustomButton(value: 0)
// let button = CustomButton() // also works
button.setTitle("Hello", for: .normal)


// auto layout
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(button)
button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
button.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true


print(button.myValue) // prints 0
}


}

2. Create your UIButton subclass with a convenience initializer

This solution allows you to create instances of your UIButton subclass with the appropriate value for your property. With this solution, you can only create instances of your UIButton subclass programmatically.

import UIKit


class CustomButton: UIButton {


var myValue: Int


convenience init(squareOf value: Int) {
self.init(value: value * value)
}


required init(value: Int = 0) {
// set myValue before super.init is called
self.myValue = value


super.init(frame: .zero)


// set other operations after super.init, if required
backgroundColor = .red
}


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


}

Usage:

import UIKit


class ViewController: UIViewController {


override func viewDidLoad() {
super.viewDidLoad()


let button = CustomButton(squareOf: 10)
// let button = CustomButton(value: 100) // also works
button.setTitle("Hello", for: .normal)


// auto layout
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(button)
button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
button.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true


print(button.myValue) // prints 100
}


}

3. Create your UIButton subclass with init(frame: CGRect) initializer

With this solution, you can only create instances of your UIButton subclass programmatically.

import UIKit


class CustomButton: UIButton {


var myValue: Int


override init(frame: CGRect) {
// set myValue before super.init is called
self.myValue = 0


super.init(frame: frame)


// set other operations after super.init, if required
backgroundColor = .red
}


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


}

Usage:

import UIKit


class ViewController: UIViewController {


override func viewDidLoad() {
super.viewDidLoad()


let button = CustomButton(frame: .zero)
//let button = CustomButton() // also works
button.setTitle("Hello", for: .normal)


// auto layout
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(button)
button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
button.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true


print(button.myValue) // prints 0
}


}

4. Create your UIButton subclass with init?(coder aDecoder: NSCoder) initializer

With this solution, you can create instances of your UIButton subclass from Storyboard.

import UIKit


class CustomButton: UIButton {


var myValue: Int


required init?(coder aDecoder: NSCoder) {
// set myValue before super.init is called
self.myValue = 0


super.init(coder: aDecoder)


// set other operations after super.init, if required
backgroundColor = .red
}


}

Usage:

import UIKit


class ViewController: UIViewController {


@IBOutlet weak var button: CustomButton!


override func viewDidLoad() {
super.viewDidLoad()


print(button.myValue) // prints 0
}


}

5. Create your UIButton subclass with init(frame: CGRect) and init?(coder aDecoder: NSCoder) initializers

With this solution, you can create instances of your UIButton subclass programmatically or from Storyboard.

import UIKit


class CustomButton: UIButton {


var myValue: Int


override init(frame: CGRect) {
// set myValue before super.init is called
self.myValue = 0


super.init(frame: frame)


// set other operations after super.init, if required
backgroundColor = .red
}


required init?(coder aDecoder: NSCoder) {
// set myValue before super.init is called
self.myValue = 0


super.init(coder: aDecoder)


// set other operations after super.init if required
backgroundColor = .red
}


}

6. Create your UIButton subclass with a default property value for your property

As an alternative to the previous solutions, you can assign an initial value to your property outside of the initializers.

import UIKit


class CustomButton: UIButton {


var myValue: Int = 0


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


// set other operations after super.init, if required
backgroundColor = .red
}


required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)


// set other operations after super.init if required
backgroundColor = .red
}


}

7. Create your UIButton subclass with your property having an optional type

If you don't want to / can't set a default value to your property when your button is created, you must set your property type as an optional.

import UIKit


class CustomButton: UIButton {


var myValue: Int? = nil


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


// set other operations after super.init, if required
backgroundColor = .red
}


required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)


// set other operations after super.init if required
backgroundColor = .red
}


}

Note: I'm using Swift 3 in Xcode 8.3.3

This is a simple and easy workaround I've been using when needing to add custom properties and methods to a UIButton:

class CVSTButton: UIButton {


var cvstPosition: Double


static func button(withCVSTPosition cvstPosition: Double) -> CVSTButton {


let button = CVSTButton(type: .detailDisclosure) // You may adjust the initializer used to suit your needs.


button.cvstPosition = cvstPosition // Then you can simply set the the properties (which are passed as arguments to the factor/class method)


return button


}


}

To use it:

let cvstButton = CVSTButton.button(withCVSTPosition: 2.0)