I was trying to figure out how to create a custom view using xib files. In this question the next method is used.
NSBundle.mainBundle().loadNibNamed("CardView", owner: nil, options: nil)[0] as! UIView
Cocoa has the same method,however, this method has changed in swift 3 to loadNibNamed(_:owner:topLevelObjects:), which returns Bool, and previous code generates "Type Bool has no subscript members" error, which is obvious, since the return type is Bool.
So, my question is how to a load view from xib file in Swift 3
First of all the method has not been changed in Swift 3.
loadNibNamed(_:owner:topLevelObjects:)
has been introduced in macOS 10.8 and was present in all versions of Swift. However loadNibNamed(nibName:owner:options:)
has been dropped in Swift 3.
The signature of the method is
func loadNibNamed(_ nibName: String,
owner: Any?,
topLevelObjects: AutoreleasingUnsafeMutablePointer<NSArray>?) -> Bool
so you have to create an pointer to get the array of the views on return.
var topLevelObjects = NSArray()
if Bundle.main.loadNibNamed("CardView", owner: self, topLevelObjects: &topLevelObjects) {
let views = (topLevelObjects as Array).filter { $0 is NSView }
return views[0] as! NSView
}
Edit: I updated the answer to filter the NSView
instance reliably.
In Swift 4 the syntax slightly changed and using first(where
is more efficient:
var topLevelObjects : NSArray?
if Bundle.main.loadNibNamed(assistantNib, owner: self, topLevelObjects: &topLevelObjects) {
return topLevelObjects!.first(where: { $0 is NSView }) as? NSView
}
Swift 4 version of @vadian's answer
var topLevelObjects: NSArray?
if Bundle.main.loadNibNamed(NSNib.Name(rawValue: nibName), owner: self, topLevelObjects: &topLevelObjects) {
return topLevelObjects?.first(where: { $0 is NSView } ) as? NSView
}
I wrote an extension that is safe and makes it easy to load from nib:
extension NSView {
class func fromNib<T: NSView>() -> T? {
var viewArray = NSArray()
guard Bundle.main.loadNibNamed(String(describing: T.self), owner: nil, topLevelObjects: &viewArray) else {
return nil
}
return viewArray.first(where: { $0 is T }) as? T
}
}
Then just use like this:
let view: CustomView = .fromNib()
Whether CustomView
is a NSView
subclass and also CustomView.xib
.
来源:https://stackoverflow.com/questions/40570872/swift-3-load-xib-nsbundle-mainbundle-loadnibnamed-return-bool