Use Xib in Storyboard / 在StoryBoard里面使用自定义Xib

如何使用Xib创建自定义UIView

新建一个空白View xib文件
image.png
image.png
关联xib文件和code 文件

有两种方式去关联xib文件和代码文件,第一种就是设置file's owner 的 custom class,另外一种就是在view那里去设置custom class

image.png

File's owner和View's custom class的区别

File's owner custom class View's custom class
NSObject UIView

根据上图也可以看到,File's owner 的custom class对应是NSObject类型,而View‘s custom class是UIView类型。

使用View's custom class创建关联
image.png

XibView.swift 里面的代码

import UIKit

@IBDesignable
class XibView: UIView {

    let nibName = "XibView"

    override init(frame: CGRect) {
        super.init(frame: frame)
        print(#function)
        commonInit()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        print(#function)
    }
    
    func commonInit() {
        guard let view = loadViewFromNib() else { return }
        view.frame = self.bounds
        addSubview(view)
    }

    func loadViewFromNib() -> UIView? {
        print(#function)
        guard let view = Bundle.main.loadNibNamed("XibView", owner: nil, options: nil)?.first as? UIView else { return nil }
        return view
    }

}

在ViewController中的使用

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let xibView = XibView(frame: view.bounds)
        view.addSubview(xibView)
    }

}
运行✅
image.png

可以看到先调用 init去初始化,init方法里面去调用loadNib方法,而loadNib会触发required init?(coder aDecoder: NSCoder)

这个时候得说下required init?(coder aDecoder: NSCoder)的调用,一般代码去初始化一个view的时候,会走init(frame: CGRect),而不会走required init?(coder aDecoder: NSCoder). 需要去load Nib的时候才会调用required init?(coder aDecoder: NSCoder),也就是说用StoryBoard拉控件的形式只会调用required init?(coder aDecoder: NSCoder)

在StoryBoard中使用

1⃣️ XibView.swift 里面需要修改部分代码,即是在required init?(coder aDecoder: NSCoder)里面调用私有方法commonInit()去loadNib

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        print(#function)
        commonInit()
    }

2⃣️ 在StoryBoard拉一个UIView,将class设置成自定义view的类就可以引用了

image.png

Run -> ….. 运行❌

122.gif

❌ 所以!如果使用View's custom class去关联xib和代码文件,并且要在storyboard使用这个自定义的xib view的时候,我们必须在required init?(coder aDecoder: NSCoder)里面去调用commonInit()去load xib里面添加的控件(用storyboard拉控件的形式,不会走init(frame: CGRect)),我们将会陷入初始化的死循环。

使用File's owner

Apple官方文档给出关于File's owner的说明:

About the File’s Owner

One of the most important objects in a nib file is the File’s Owner object. Unlike interface objects, the File’s Owner object is a placeholder object that is not created when the nib file is loaded. Instead, you create this object in your code and pass it to the nib-loading code. The reason this object is so important is that it is the main link between your application code and the contents of the nib file. More specifically, it is the controller object that is responsible for the contents of the nib file.

In Xcode, you can create connections between the File’s Owner and the other interface objects in your nib file. When you load the nib file, the nib-loading code recreates these connections using the replacement object you specify. This allows your object to reference objects in the nib file and receive messages from the interface objects automatically.

文件中最重要的对象之一是File的Owner对象。与接口对象不同,File的Owner对象是一个占位符对象,在加载nib文件时不会创建占位符对象。相反,您在代码中创建此对象并将其传递给nib加载代码。这个对象如此重要的原因是它是应用程序代码和nib文件内容之间的主要链接。更具体地说,它是控制器对象,负责nib文件的内容。
在Xcode中,您可以在文件所有者和nib文件中的其他接口对象之间创建连接。加载nib文件时,nib加载代码使用您指定的替换对象重新创建这些连接。这允许您的对象引用nib文件中的对象并自动从接口对象接收消息.

Bundle.main.loadNibNamed("XibView", owner: self, options: nil)?.first as? UIView

可以看到此时我们把初始化好的owner对象作为参数传递进去了。

在Demo中的使用

image.png

XibView.swift 文件只需要修改loadNib部分代码

func loadViewFromNib() -> UIView? {
        print(#function)
        guard let view = Bundle.main.loadNibNamed("XibView", owner: self, options: nil)?.first as? UIView else { return nil }
        return view
    }

StoryBoard中还是拉一个UIView控件,className改为自定义类型。

运行✅

可以在StoryBoard里面使用Xib自定义的View了 🎉🎉🎉

image.png

总结

File’s Owner 和 View custom class都是用于xib跟代码文件建立关联的。

在StoryBoard里面使用自定义xib时候,只会走required init?(coder aDecoder: NSCoder)方法,所以需要在里面调用loadNib加载添加在xib上的控件。

使用File’s Owner,用代码去loadNib的时候,不会走required init?(coder aDecoder: NSCoder)方法。但是使用View custom class时候会,这也就是为什么使用View custom class时候造成死循环的原因。

image.png

所以,如果需要在StoryBoard里面使用Xib自定义的View,需要设置File’s Owner,而不是View custom class.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容