Reputation: 2249
I have a viewcontroller with a custom view area on the top, as seen in the below image
I want to load a custom xib into this area and I am struggling to do so.
I created a ABC.swift
file which is a subclass of NSView and a .xib file with the same name.
In the .xib file from the identity inspector I set the class ABC.
Then in my viewcontroller's viewDidLoad()
I try to do the following
let abcView = Bundle.main.loadNibNamed("ABC", owner: self, topLevelObjects: nil) as ABC
I also created an outlet for the custom view in my vc
then in viewDidLoad()
customView.addSubview(abcView)
But this not working as abcView is of type Bool. Can anyone tell me what am I doing wrong? What is the best way to achieve my goal?
Upvotes: 2
Views: 3276
Reputation: 408
A slightly more compact version of answer already given
extension NSView {
static func loadFromNib(nibName: String, owner: Any? = nil) -> NSView? {
var arrayWithObjects: NSArray?
let nibLoaded = Bundle.main.loadNibNamed(NSNib.Name(rawValue: nibName),
owner: owner,
topLevelObjects: &arrayWithObjects)
if nibLoaded {
return arrayWithObjects?.first(where: { $0 is NSView }) as? NSView
}
return nil
}
}
Upvotes: 0
Reputation: 613
I use the following Extension on NSView
: (same as answer given by user Accepted Answer
)
import Foundation
import Cocoa
extension NSView {
static func loadFromNib(nibName: String, owner: Any?) -> NSView? {
var arrayWithObjects: NSArray?
let nibLoaded = Bundle.main.loadNibNamed(NSNib.Name(rawValue: nibName), owner: owner, topLevelObjects: &arrayWithObjects)
if nibLoaded {
guard let unwrappedObjectArray = arrayWithObjects else { return nil }
for object in unwrappedObjectArray {
if object is NSView {
return object as? NSView
}
}
return nil
} else {
return nil
}
}
}
This is how to use it in loadView()
of an NSViewController
:
if let loadedNavButtons: NavigationButtonsView = NSView.loadFromNib(nibName: "NavigationButtonsView", owner: self) as? NavigationButtonsView {
// Do whatever you want with loadedNavButtons
}
Works in Swift 4 , XCode 9.2
Upvotes: 3
Reputation: 188
As of this writing, macOS only has a legacy means of bundle loading: func loadNibNamed(_ nibName: NSNib.Name, owner: Any?, topLevelObjects: AutoreleasingUnsafeMutablePointer<NSArray?>?) -> Bool
.
It shall pass the top-level objects of the nib in the array you supplied as the last argument:
var objs = NSArray()
Bundle.main.loadNibNamed("MyScreen", owner: self, topLevelObjects: &objs)
Be sure to check it returned true. Otherwise it means it could not load the desired nib.
After it's loaded, the objects in the left-hand menu in the Interface Builder are available in your code. If you have a View in your nib, you can add it as a subview:
for obj in objs {
if obj is MyViewClass {
// Now we are sure that the obj is really a view of the desired class
self.someView.addSubview(obj)
}
}
Upvotes: 0