I am looking for good practice how to initialize subviews (e.g. text of labels, or buttons) of a custom view that are connected via IBOutlets.
The custom view's view controller is calling the xib file on init like this:
final class MenuDiscoveryListView : NSView, MenuDiscoveryListViewProtocol {
let C_NAME_XIB = "MenuDiscoveryList"
@IBOutlet weak var labelStatus: NSTextField!
@IBOutlet weak var stackList: NSStackView!
var presenter : MenuDiscoveryListPresenter?
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
xibInit(autoXibLoading: true)
}
required init?(coder decoder: NSCoder) {
super.init(coder: decoder)
xibInit(autoXibLoading: false)
}
/// Routine for initializating view
///
/// - Parameter loadXib: Select if auto-load from related xib file into the view container is desired. Select TRUE, if function is called from NSView's `init(frame frameRect: NSRect)`.
func xibInit(autoXibLoading loadXib : Bool = true) {
// Load xib item
if loadXib {
var topLevelObjects : NSArray?
if Bundle(for: type(of: self)).loadNibNamed(C_NAME_XIB, owner: self, topLevelObjects: &topLevelObjects) {
if let contentView = topLevelObjects!.first(where: { $0 is NSView }) as? NSView {
// Add loaded view from xib file into container as subview
self.addSubview(contentView)
// Transfer dimensions
self.frame = contentView.frame
// Define constraints
self.translatesAutoresizingMaskIntoConstraints = false
contentView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint(item: self, attribute: .leading, relatedBy: .equal, toItem: contentView, attribute: .leading, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: self, attribute: .trailing, relatedBy: .equal, toItem: contentView, attribute: .trailing, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: contentView, attribute: .top, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: self, attribute: .bottom, relatedBy: .equal, toItem: contentView, attribute: .bottom, multiplier: 1.0, constant: 0).isActive = true
}
}
}
}
}
The init of the view controller is called from another view controller's presenter module in a very classy way:
let view = MenuHeaderItemView()
However, after initializing the view controller, as expected, the IBOutlets found nil. Nevertheless, I wanted to set a string value of labelStatus
right after initializing the view (e.g. standard string) through NSBundle
's (or Bundle
's) loadNibName
without waiting for awakeFromNib
.
What is a good practice or approach to do this synchronously and access the IBOutlets right after the init?
EDIT:
I have realized that labelStatus
and stackList
are successfully loaded in contentView
:
Is there any elegant way to copy their content/instantiation over to the IBOutlets?