先日、iOSDC2017があり非常に楽しかったということを伝えたいのと、自分も何かアウトプットしなければと思ったためにニッチですが1つ最近調べたことを紹介したいと思います。
NSNib
NSNibを使って.xibファイルからViewを生成しようとしたとき、UINibの感覚で使おうと思ってたらinstantiateの使い型が異なっていて困ってしまいました。
func instantiate(withOwner owner: Any?, topLevelObjects: AutoreleasingUnsafeMutablePointer<NSArray?>?) -> Bool
AutoreleasingUnsafeMutablePointerってなんだろう?🤔
最初よくわからなくてAutoreleasingUnsafeMutablePointer.initから頑張って作ったりしてたのですが、ここに載ってたコードによると話は単純で、Cライクにポインタを渡すように書けばいいだけみたいでした
instantiateの使い方
var topLevelObjects: NSArray = []
guard nib.instantiate(withOwner: owner, topLevelObjects: &topLevelObjects) else {
...
}
...
これを踏まえて、AppStoryboardの実装を参考にしてNSNib用にextensionを作成しました
コード
NSNib+instantiate.swift
import Foundation
import Cocoa
enum AppNib: String {
case MyNibName1
case MyNibName2
var instance: NSNib {
return NSNib(nibNamed: self.rawValue, bundle: Bundle.main)!
}
func view<T: NSView>(viewClass: T.Type) -> T {
for object in instance.instantiate(withOwner: nil) {
if let view = object as? T {
return view
}
}
fatalError("\(T.className()) is not found in \(self.rawValue) Nib.")
}
}
extension NSView {
static func instantiate(fromNib appNib: AppNib) -> Self {
return appNib.view(viewClass: self)
}
}
extension NSNib {
public func instantiate(withOwner owner: Any?) -> [Any] {
var topLevelObjects: NSArray = []
guard instantiate(withOwner: owner, topLevelObjects: &topLevelObjects) else {
return []
}
return topLevelObjects as? [Any] ?? []
}
}
利用方法
let myview = MyView.instantiate(fromNib: .MyNibName1)
.xibのファイル名をあらかじめenumのAppNibに定義しておく必要があります
おわりに
iOSDC2017楽しかったです!