Reputation: 2245
So I learned in Swift we should use two-phase initialisation: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html
One of the rules is: "An initializer cannot call any instance methods, read the values of any instance properties, or refer to self as a value until after the first phase of initialization is complete."
This prevents placing chunks of code in instance methods, so I guess class methods should be used? What do you think? Any alternative solutions?
To illustrate what I mean here are 3 code samples:
Unrefactored code:
@objc class MYChatBarButton: UIBarButtonItem {
let badgeLabel: UILabel
init(target: AnyObject, selector: Selector) {
let button = UIButton.buttonWithType(.Custom) as UIButton
button.frame = CGRectMake(0, 0, 35, 44)
button.addTarget(target, action: selector, forControlEvents: .TouchUpInside)
button.tintColor = UIColor.whiteColor()
button.setImage(UIImage(named: "chat_icon")?.imageWithRenderingMode(.AlwaysTemplate), forState: .Normal)
button.imageEdgeInsets = UIEdgeInsets(top: 0, left: 7, bottom: 5, right: 0)
badgeLabel = UILabel(frame: CGRectMake(0, 0, 15, 15))
badgeLabel.backgroundColor = UIColor.clearColor()
badgeLabel.textColor = UIColor.whiteColor()
badgeLabel.textAlignment = .Center
badgeLabel.text = "0"
badgeLabel.userInteractionEnabled = false
button.addSubview(badgeLabel)
super.init(customView: button)
}
}
The way I expected to do refactoring but it doesn't work:
@objc class MYChatBarButton: UIBarButtonItem {
let badgeLabel: UILabel
init(target: AnyObject, selector: Selector) {
let button = createButton(target, selector: selector)
createBadgeLabel()
button.addSubview(badgeLabel)
super.init(customView: button)
}
func createButton(target: AnyObject, selector: Selector) -> UIButton {
let button = UIButton.buttonWithType(.Custom) as UIButton
button.frame = CGRectMake(0, 0, 35, 44)
button.addTarget(target, action: selector, forControlEvents: .TouchUpInside)
button.tintColor = UIColor.whiteColor()
button.setImage(UIImage(named: "chat_icon")?.imageWithRenderingMode(.AlwaysTemplate), forState: .Normal)
button.imageEdgeInsets = UIEdgeInsets(top: 0, left: 7, bottom: 5, right: 0)
return button
}
func createBadgeLabel() {
badgeLabel = UILabel(frame: CGRectMake(0, 0, 15, 15))
badgeLabel.backgroundColor = UIColor.clearColor()
badgeLabel.textColor = UIColor.whiteColor()
badgeLabel.textAlignment = .Center
badgeLabel.text = "0"
badgeLabel.userInteractionEnabled = false
}
}
The way it should probably be done (but I don't like it so very much):
@objc class MYChatBarButton: UIBarButtonItem {
let badgeLabel: UILabel
init(target: AnyObject, selector: Selector) {
let button = MYChatBarButton.createButton(target, selector: selector)
badgeLabel = MYChatBarButton.createBadgeLabel()
button.addSubview(badgeLabel)
super.init(customView: button)
}
class func createButton(target: AnyObject, selector: Selector) -> UIButton {
let button = UIButton.buttonWithType(.Custom) as UIButton
button.frame = CGRectMake(0, 0, 35, 44)
button.addTarget(target, action: selector, forControlEvents: .TouchUpInside)
button.tintColor = UIColor.whiteColor()
button.setImage(UIImage(named: "chat_icon")?.imageWithRenderingMode(.AlwaysTemplate), forState: .Normal)
button.imageEdgeInsets = UIEdgeInsets(top: 0, left: 7, bottom: 5, right: 0)
return button
}
class func createBadgeLabel() -> UILabel {
let bl = UILabel(frame: CGRectMake(0, 0, 15, 15))
bl.backgroundColor = UIColor.clearColor()
bl.textColor = UIColor.whiteColor()
bl.textAlignment = .Center
bl.text = "0"
bl.userInteractionEnabled = false
}
}
Upvotes: 4
Views: 831
Reputation: 51911
At least, you can isolate the badgeLabel
creation:
@objc class MYChatBarButton: UIBarButtonItem {
let badgeLabel: UILabel = {
let bl = UILabel(frame: CGRectMake(0, 0, 15, 15))
bl.backgroundColor = UIColor.clearColor()
bl.textColor = UIColor.whiteColor()
bl.textAlignment = .Center
bl.text = "0"
bl.userInteractionEnabled = false
return bl
}()
let button: UIButton = {
let button = UIButton.buttonWithType(.Custom) as UIButton
button.frame = CGRectMake(0, 0, 35, 44)
button.tintColor = UIColor.whiteColor()
button.setImage(UIImage(named: "chat_icon")?.imageWithRenderingMode(.AlwaysTemplate), forState: .Normal)
button.imageEdgeInsets = UIEdgeInsets(top: 0, left: 7, bottom: 5, right: 0)
return button
}()
init(target: AnyObject, selector: Selector) {
button.addTarget(target, action: selector, forControlEvents: .TouchUpInside)
button.addSubview(badgeLabel)
super.init(customView: button)
}
I don't know how to do this without property.
Upvotes: 2