Xib 和 Storyboard 中, 右侧控制面板中都有一个 Custom Class 属性如下图:
Xib:
Storyboard :
Custom Class 中的 Class 选项用来自定义视图或控制器的类型
本文重点介绍 xib 中, 设置 File's owner 的 Custom Class 和 设置 View 的 Custom Class 的区别
关联 File's owner
File's Owner 是一个 Object 控件, 即 storyboard 中那个立方体图形:
上图 Object 控件简介: object 控件为 Interface Builder 中不能直接获取的对象提供一个模板, 你可以将这个 object 实例化为你在 Custom Class 的 Class 中指定类型的实例变量.
也就是说给 xib 中 File's owner 的 Custom Class Class 设置一个类型, 则 File's owner 就是该类型的一个实例
关联 File's owner 的 Custom Class
1.直接在 storyboard 中使用, 使用方法参考:
【iOS】Storyboard加载Xib自定义view(Swift)
2.代码中使用, 重写 init 方法, 将 xib 中的 View 拉为约束 contentView 添加在 self :
方法一: 直接在自定义类中获取 View
@IBOutlet var contentView: UIView!//xib 中的 View 拉为约束 contentView
@IBOutlet weak var label: UILabel!
//代码创建, 执行此方法, 不执行 init?(coder aDecoder: NSCoder)
override init(frame: CGRect) {
super.init(frame: frame)
awakeFromNib()
}
//添加在 storyboard 上, 执行此方法
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func awakeFromNib() {
super.awakeFromNib()
setupContentView()
}
func setupContentView() {
//owner 一定要为 self, 不能为 nil
let contentView = Bundle.main.loadNibNamed("CustomView_Fileowner", owner: self, options: nil)?.first as! UIView
contentView.frame = self.bounds
contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
addSubview(contentView)
}
方法二: 使用 Swift 的协议, 在协议扩展中获取 View 并添加
protocol NibLoadableProtocol { }
extension NibLoadableProtocol where Self : UIView {
//设置 File's Owner 的 CustomClass
//实例方法
func loadNibFileOwner(_ nibNmae: String? = nil) -> UIView {
//获取实例的类型
let object: AnyObject = object_getClass(self)!
//"\(object)": AntennaParameters.XXXXXX
//获取真正的类型名
let className = type(of: object).description().components(separatedBy: ".").last
let contentView = Bundle.main.loadNibNamed(nibNmae ?? className!, owner: self, options: nil)?.first as! UIView
contentView.frame = self.bounds
contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
addSubview(contentView)
return contentView
}
}
//让 CustomView_Fileowner 服从协议
extension CustomView_Fileowner: NibLoadableProtocol { }
@IBOutlet var contentView: UIView!
@IBOutlet weak var label: UILabel!
//代码创建, 执行此方法, 不执行 init?(coder aDecoder: NSCoder)
override init(frame: CGRect) {
super.init(frame: frame)
awakeFromNib()
}
//添加在 storyboard 上, 执行此方法
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func awakeFromNib() {
super.awakeFromNib()
//协议方法
contentView = loadNibFileOwner()
}
关联 View 的 Custom Class
1.使用类方法
//View 中, 类方法
class func newInstance() -> CustomView_View {
//owner 为 nil
return Bundle.main.loadNibNamed("CustomView_View", owner: nil, options: nil)?.first as! CustomView_View
}
// Controller 中
//使用类型方法创建
let viewView = CustomView_View.newInstance()
viewView.frame = CGRect(x: 50, y: 400, width: 200, height: 100)
view.addSubview(viewView)
2.使用协议扩展
protocol NibLoadableProtocol { }
extension NibLoadableProtocol where Self : UIView {
/*
static func loadNib(_ nibNmae :String = "") -> Self{
let nib = nibNmae == "" ? "\(self)" : nibNmae
return Bundle.main.loadNibNamed(nib, owner: nil, options: nil)?.first as! Self
}
*/
//类型方法
static func loadNib(_ nibNmae: String? = nil) -> Self {
return Bundle.main.loadNibNamed(nibNmae ?? "\(self)", owner: nil, options: nil)?.first as! Self
}
}
extension CustomView_View: NibLoadableProtocol { }
//使用协议扩展创建, 类型方法
let viewView = CustomView_View.loadNib()
viewView.frame = CGRect(x: 50, y: 510, width: 200, height: 100)
view.addSubview(viewView)
总结:
关联 File's Owner :
则 self 是 Custom Class自定义类型的一个实例, 要将 View 拉为约束添加在 self, 可以直接添加在 storyboard 上使用, 在代码中使用时, 要使用对象方法, Bundle.main.loadNibNamed 方法中 owner 为 self
关联 View :
则 self 是 Custom Class自定义类型, 类型不能直接添加在 storyboard, 代码中, 代码中使用时, 要使用类型方法, Bundle.main.loadNibNamed 方法中 owner 为 nil