When using IB to design a custom control (and layout elements in the custom control) I hit an issue for which the work around was described here http://blog.boxuanzhang.me/custom-reusable-uiview-with-xib/ and involves putting an "if" statement "if self.subview.count == 0" into the mix, to stop an infinite recursion loop happing. Refer to the work around point in the custom control swift file below.
Question - Is there a better way to do this?
import UIKit
@IBDesignable
class CustomControlView: UIView {
// override initializers
override init(frame: CGRect) {
super.init(frame: frame)
xibSetup()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xibSetup()
}
func xibSetup() {
if self.subview.count == 0 { // *** WORK AROUND ***
view = loadViewFromNib()
view.frame = bounds
view.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
addSubview(view)
}
}
func loadViewFromNib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: nibName, bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
}
Question - Is there a better way to do this?
Kinda depends on what 'this' is.
If you simply setup your view in a storyboard and set the custom class you can remove that xibSetup() code. This is the normal way of doing things. If you're going to have multiple instances of the view you can simply use copy and paste in the storyboard to make as many instances as you want. That's most likely how I would do it.
If you have your heart set on using a nib to layout your view then you have all the code to do that but it's organized poorly. I would add a static method to your class like
static func addMyCustomViewToView(parentView: UIView) -> CustomView
then load the view from the nib as in your loadViewFromNib() and then set the frame, addSubview(), etc. as in your xibSetup() but using the parentView. In your existing code remove xibSetup from the init methods. initWithFrame won't work in this case but it's pointless anyway since you'll always use addMyCustomViewToView to build one of these things.
The idea of having a placeholder view whose purpose is to hold the frame of a view that will be added later isn't that uncommon. But normally the class of that placeholder view isn't the same as the view that's added to replace it. That's the source of your recursion. I guess another way to fix this would be to have two custom classes. One is the PlaceHolder view and the second is your CustomView. The PlaceHolder view would load the CustomView and addSubview(). The PlaceHolder view would have an @property for the CustomView. You might like this solution the best as it's most similar to the code you show.
Another way to reuse the view class would be to do all the subview construction in code.