Apple's tutorial describes the difference between init(frame:)
and init?(coder:)
as
You typically create a view in one of two ways: by programatically initializing the view, or by allowing the view to be loaded by the storyboard. There’s a corresponding initializer for each approach:
init(frame:)
for programatically initializing the view andinit?(coder:)
for loading the view from the storyboard. You will need to implement both of these methods in your custom control. While designing the app, Interface Builder programatically instantiates the view when you add it to the canvas. At runtime, your app loads the view from the storyboard.
I feel so confused by the description "programtically initializing" and "loaded by the storyboard". Say I have a subclass of UIView
called MyView
, does "programtically initialization" mean I write code to add an instance of MyView
to somewhere like:
override func viewDidLoad() {
super.viewDidLoad()
let myView = MyView() // init(frame:) get invoked here??
}
while init?(coder:)
get called when in Main.storyboard
I drag a UIView
from object library and then in the identity inspector I set its class to MyView
?
Besides, in my xcode project, these two methods end up with different layout for simulator and Main.storyboard
with the same code:
import UIKit
@IBDesignable
class RecordView: UIView {
@IBInspectable
var borderColor: UIColor = UIColor.clear {
didSet {
self.layer.borderColor = borderColor.cgColor
}
}
@IBInspectable
var borderWidth: CGFloat = 20 {
didSet {
layer.borderWidth = borderWidth
}
}
@IBInspectable
var cornerRadius: CGFloat = 100 {
didSet {
layer.cornerRadius = cornerRadius
}
}
private var fillView = UIView()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupFillView()
}
override init(frame: CGRect) {
super.init(frame: frame)
setupFillView()
}
private func setupFillView() {
let radius = (self.cornerRadius - self.borderWidth) * 0.95
fillView.frame = CGRect(origin: CGPoint.zero, size: CGSize(width: radius * 2, height: radius * 2))
fillView.center = CGPoint(x: self.bounds.midX, y: self.bounds.midY)
fillView.layer.cornerRadius = radius
fillView.backgroundColor = UIColor.red
self.addSubview(fillView)
}
override func layoutSubviews() {
super.layoutSubviews()
}
func didClick() {
UIView.animate(withDuration: 1.0, animations: {
self.fillView.transform = CGAffineTransform(scaleX: 0.6, y: 0.6)
}) { (true) in
print()
}
}
}
Why do they behave differently? (I drag a UIView
from object library and set its class to RecordView)