我用稍微不同的方法解决了这个问题。 Swift 5 中的代码。
如果您想创建从 .xib 加载的 NSView,例如addSubview 和代码中的约束,这里是示例:
public static func instantiateView<View: NSView>(for type: View.Type = View.self) -> View {
let bundle = Bundle(for: type)
let nibName = String(describing: type)
guard bundle.path(forResource: nibName, ofType: "nib") != nil else {
return View(frame: .zero)
}
var topLevelArray: NSArray?
bundle.loadNibNamed(NSNib.Name(nibName), owner: nil, topLevelObjects: &topLevelArray)
guard let results = topLevelArray as? [Any],
let foundedView = results.last(where: {$0 is Self}),
let view = foundedView as? View else {
fatalError("NIB with name \"\(nibName)\" does not exist.")
}
return view
}
public func instantiateView() -> NSView {
guard subviews.isEmpty else {
return self
}
let loadedView = NSView.instantiateView(for: type(of: self))
loadedView.frame = frame
loadedView.autoresizingMask = autoresizingMask
loadedView.translatesAutoresizingMaskIntoConstraints = translatesAutoresizingMaskIntoConstraints
loadedView.addConstraints(constraints.compactMap { ctr -> NSLayoutConstraint? in
guard let srcFirstItem = ctr.firstItem as? NSView else {
return nil
}
let dstFirstItem = srcFirstItem == self ? loadedView : srcFirstItem
let srcSecondItem = ctr.secondItem as? NSView
let dstSecondItem = srcSecondItem == self ? loadedView : srcSecondItem
return NSLayoutConstraint(item: dstFirstItem,
attribute: ctr.firstAttribute,
relatedBy: ctr.relation,
toItem: dstSecondItem,
attribute: ctr.secondAttribute,
multiplier: ctr.multiplier,
constant: ctr.constant)
})
return loadedView
}
如果没有与类名同名的 .xib 文件,则代码将仅从代码创建类。如果有人想以相同的方式从代码和 xib 文件创建视图,并保持您的代码井井有条,这是非常好的解决方案 (IMO)。
.xib文件名和类名必须同名:
在.xib 文件中你应该只有一个视图对象,并且这个对象必须有设置类:
你需要在类代码中添加instantiateView() in awakeAfter 例如:
import Cocoa
internal class ExampleView: NSView {
internal override func awakeAfter(using coder: NSCoder) -> Any? {
return instantiateView() // You need to add this line to load view
}
internal override func awakeFromNib() {
super.awakeFromNib()
initialization()
}
}
extension ExampleView {
private func initialization() {
// Preapre view after view did load (all IBOutlets are connected)
}
}
要实例化这个视图,例如ViewController 你可以这样创建视图:
let exampleView: ExampleView = .instantiateView() 或
let exampleView: ExampleView = ExampleView.instantiateView()
但 Swift 有时会遇到这样的实例化问题:
let exampleView = ExampleView.instantiateView()
在您的控制器中的viewDidLoad() 中,您可以将此视图添加为子视图:
internal override func viewDidLoad() {
super.viewDidLoad()
exampleView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(exampleView)
NSLayoutConstraint.activate(
[exampleView.topAnchor.constraint(equalTo: view.topAnchor),
exampleView.leftAnchor.constraint(equalTo: view.leftAnchor),
exampleView.rightAnchor.constraint(equalTo: view.rightAnchor),
exampleView.bottomAnchor.constraint(equalTo: view.bottomAnchor)]
)
}