一天一点xib:8高冷的xib

作者: 二亮子 | 来源:发表于2016-01-22 00:29 被阅读4636次

引言

学到这里,xib给我带来的帮助已经很大了,最大的莫过于UI控件的创建、属性的赋值再也不用写代码,就UI开发来说大大减少了代码,而且设置delegate、addTarget、属性声明等也不用自己写代码了。SB的segue使我们的页面跳转也不需要写代码了,还有强大的cell功能更是在开发中起到了很大的作用,除此之外,xib还有一些高冷功能,这些功能有些很少有人使用,你在网上也几乎看不到关于它的文章,但是它们确实是很好用,下面我们就来一起看看。

是时候总结一下了

当我们在代码中打出IB的时候,代码提示会是这样的:

在开始介绍一些高冷用法之前,我们先总结一下它们:

IBAction与IBOutlet

这是我们最常接触的两个,大家对它们已经有了很好的认识,这里只简单的说一下。

对于一个类来说,方法和属性(在这里属性与字段合在一起表示一个概念)是最重要的两个要素,而IBAction与IBOutlet就是分别标识方法与属性的,它们标识着由它们修饰的方法和属性是来自xib的,我猜它们是给编译器看的。

IBInspectable

在OC中使用IBInspectable,在swift中使用@IBInspectable

它是xcode6引入的新功能,它修饰的属性或者实例变量,会显示在xib中的属性栏中(Show the Attributes inspector),我们之前讲的东西都是xib是如何影响代码的,而IBInspectable是可以用代码影响xib的,可能我的表述不是很正确,还是看一个具体例子吧。

@interface ViewController : UIViewController

//gj_testFlag用IBInspectable修饰后,就能在xib中看到这个属性了,当然也可以用xib进行赋值了
@property (assign, nonatomic) IBInspectable BOOL gj_testFlag;

@end

这个例子这是为了说明IBInspectable的用法,具体应用没有太大意义,但是如果我们会灵活运用IBInspectable就会带来极大的方便,其实xib的好多用法都有着意想不到的效果,大家可以在各个情况下去尝试,这是一件很酷的事。

IB_DESIGNABLE

在OC中将IB_DESIGNABLE写在@implementation前,在swift中将@IBDesignable写在class前

它也是xcode6引入的新功能,它的作用是可以在不运行的情况下把你的代码显示在xib或SB文件中。

两点说明:

1.这是一个针对UI显示的功能,所以只能是在UIView及其子类或者NSView及其子类上生效。

2.要想使IBDesignable起作用必须把代码写在drawRect里才能显示,同样的代码,我写在了awakeFromNib里就不会再xib中看出效果,只有写在了drawRect才可以。

举个例子:

我们建一个工程,新建一个TestView类继承自UIVIew,在Main.storyboard里拖一个View,class设置为TestView,背景设置成灰色。

然后写代码:

IB_DESIGNABLE
@implementation TestView

- (void)drawRect:(CGRect)rect {
    UIBezierPath *firtPath = 
    [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 180, 180)];
    CAShapeLayer *shapeL = [CAShapeLayer layer];
    shapeL.lineWidth = 20;
    shapeL.path =firtPath.CGPath;
    shapeL.strokeStart = 0;
    shapeL.strokeEnd = 1;
    shapeL.strokeColor = [UIColor yellowColor].CGColor;
    shapeL.fillColor = [UIColor clearColor].CGColor;
    [self.layer addSublayer:shapeL];
    self.layer.cornerRadius = 30;
    self.layer.masksToBounds = YES;
}

@end

此时再看Main.storyboard中View的变化:

我们的IB_DESIGNABLE功能已经生效了

我们把下面的代码从drawRect:中剪切到awakeFromNib函数中会发现,圆角不见了,这里要特别注意。

self.layer.cornerRadius = 30;
self.layer.masksToBounds = YES;

IBOutletCollection(ClassName):

将基于IBOutlet创建的对象放在一个NSarray里。
@property (strong, nonatomic) IBOutletCollection(UIView) NSArray *testViewArr;
创建了一个array,里面放的是用IBOutlet创建的UIView.

注意最好用strong进行修饰,而且如果你声明的不是NSArray,即便是UIColor,系统也不会报错,你打印这个color发现,系统用的还是NSArray。这个array的顺序是连线时候的顺序,但是不排除不同版本的xcode会改变这个顺序,所以最好不要依赖这个顺序。

也可以像拖IBOutlet那样创建:

用xib给控件添加手势

Files Owner的应用举例

有这样一个场景,VC中有一个textfield要设置inputAccessoryView属性,该属性的view显示起来很复杂,有多个按钮,每个按钮对应不同的事件。

一般的做法是用代码写一个这样的view赋值给inputAccessoryView属性,其实这个例子可以用xib实现的更优雅,不用写代码就可以完成(当然点击每个按钮后的事件处理代码是要自己写的)。

例子中要考虑的重点是:
如果创建了一个AccessoryView.xib去拖出这样一个view,虽然不用“画”UI了,但是我们要建一个AccessoryView.h、AccessoryView.m类去与xib文件对应,在AccessoryView.m中把它上面的按钮事件记录下来,一旦触发事件,要通过delegate或通知等其他形式把事件从AccessoryView类传递给VC类,这样使事情更加的麻烦了,如何解决?

有人会想:创建AccessoryView.h、AccessoryView.m是没有必要的,因为他们除了传递事件,根本没做任何事情,这样的话就不创建他们,只有AccessoryView.xib文件,然后把xib中的按钮分别拖动到VC类中建立起IBAction的“连线”关系,事情就搞定了。

这个思路很好,但是我们会发现,并不能实现AccessoryView.xib与VC中的“连线”,因为VC类根本不认识这个xib,因此该VC是不允许这个xib通过“连线”向它内部添加代码的,如何解决这个问题?——Files Owner!

将AccessoryView.xib的Files Owner指定成该VC的类,此时再拖“连线”到VC就可以了,这样xib中按钮的事件就能直接回调到VC中我们设置的方法里了。

这是解决这个问题最简单的方法,不用写一行代码,他给我们的启示是:

xib文件是可以不依托于UIView子类、UIViewController子类单独使用的,只是这种情况比较少见,这是一个例子。

由此我们应该放开我们的思想束缚,去大胆的实践xib的各种用法。

这里再说一点:之前讲过基于UIView子类的xib的使用方法:

TestView *tView = [[NSBundle mainBundle] loadNibNamed:@"TestView" owner:self options:nil][0];

这个方法就是从bundle中找到xib文件(其实是找到被xcode编译好的nib文件)将其加载到内存中,与该xib文件是否与其他类建立了关联无关,所以这里加载xib文件也是用的此方法。

这个例子稍稍变一下需求,就是我们在一天一点xib:4简单使用xib里谈论Files Owner要说的例子了,如果点击textField的AccessoryView会有UI上的变化,或者交互的话,最好就是要创建AccessoryView.h、AccessoryView.m,然后把AccessoryView.xib分别与AccessoryView.m和VC的.m连线,UI的处理在AccessoryView.m中完成,逻辑的处理在VC的.m中完成,这样的“双连线”很好的解决了要把事件从AccessoryView.m传递给VC的.m的问题。

xib的国际化

有些app是要做国际化适配的,下面来说说xib如何做国际化,相当的简单。

1.给project添加多语言,我们以法语为例。

2.选择要国际化的xib或SB文件。

3.此时支持国际化的xib或SB文件就变成了这样:

4.下面来说说国际化中文件的组织问题:

.lproj是管理多语言相关的文件,默认工程会创建Base.lproj,里卖放xib或SB文件,我们可以在其他路径创建xib或SB文件,但是如果要使得这个文件支持国际化,系统就会把它放在Base.lproj里。我们多支持一种语言就会多创建一个.lproj文件,例如fr.lproj用于支持法语,除了Base.lproj外,其他的.lproj文件中是不放xib或SB文件的,他们会放.strings文件,.strings文件是国际化对应的重要文件,不同的语言,放在不同的.strings文件中。系统根据iOS设备当前的语言会去找到当前的.strings文件并加载里面的string,如果大家对国际化比较陌生,可以先在网上找找国际化的一些东西来看,这里默认大家对国际化是了解的。

5.开始国际化,向SB的VC中拖入一个label,显示的文字为:“你好”。拷贝object id。

6.打开xib或SB文件对应的一种语言的.strings文件(我们例子中是Main.strings(French)), 添加:

rii-xB-u6s.text = @"bonjour"

bonjour是法语中你好的意思。

7.把iOS设备的语言设置为法语,运行程序,大功告成!

两点说明

1.网上普遍流行的xib国际化的方法是用终端执行命令的方式,我个人认为,上面是最简单的方法,xib真的很强大。

2.国际化后就一定要建立一种相对应的本地化的语言,不然在切换语言的时候app还会显示之前的那种语言,这一点很重要,比如你app支持的本地语言是汉语,还想支持法语,那么一旦你国际化了,你其实要在xcode中添加两种语言,汉语和法语,生成两个.strings文件,一定切记。

User Define Runtime Attribute

之前在介绍xib右边栏的时候简单的说了一下,这是xib很高冷的一个用法,但实际上很简单,很方便,希望大家学会以后,多多使用,因为真的是太方便了。现在来具体说明。

1.拖一个view到SB的View上,为了看出效果,我这里给了它一个灰色背景。

2.设置User Define Runtime Attribute。

3.运行看效果:

是的,别怀疑,就是这么简单,把一些xib中不能设置的属性,写在这里,就可以了,弄个圆角矩形的button再也不用写代码了,方便吧。

Object

这是一个更高冷的xib用法,相对来说比较复杂,我们一点点的开始。

1.我们先建立一个Person类,继承自NSObject。

2.我们在Person类中添加一个简单的测试方法:

- (IBAction)sayHello:(id)sender {
    NSLog(@"hello person");
}

你可能会有疑问,一个继承自NSObject的类,是不能使用xib或SB的,为什么写个方法还用IBAction?而且编译器还不报错?

这里我想说:我们学习的过程其实是对现有知识、经验的不断地修正,其实科学的发展也这样。xib是可以和继承自NSObject的类发生关系的,我们往下看。

3.我们在一个VC中添加这样的代码:

#import "Person.h"

@interface ViewController : UIViewController

@property (nonatomic, strong) IBOutlet Person *aPerson;

@end

你可能同样有疑问,Person类为什么可以加IBOutlet修饰,控件栏里也没有Person类啊,为什么编译不报错?我们还是往下看。

4.我们找到ViewController对应的xib或SB文件,拖入一个button,把这个button与Person类中的sayHello:函数“连线”,你发现根本连接不上,其实也很简单,两者一点关系都没有,都不认识,怎么“连线”呢?那么我们如何让他们彼此认识?往下看。

5.在右边栏中找到Object这个对象,拖动它到左侧边栏中,把Object对象的class设置为Person,大功告成!

6.最后一步,连线,建立关系,运行测试。

这里注意,最重要的一步是要把Object对象的class设置为Person,其实xib使用中最重要地方就在class的设置,和file's Owner的设置,这是使用xib的核心。

有些人会说,这又什么卵用?

我个人认为,这种用法其实意义很大:

1.你如果遇到这种Controller需要其他类处理的情况,xib也是可以应用的,而且还是不用写什么代码,设置什么delegate,相当的方便,如果你不知道如何应用,只能说明,你之前没有想到过xib会如此的强大,可以做如此多的事情。

2.我们都熟悉Category,知道他的一个优点就是把不同的实现可以分散到不同文件中,或者把相同的功能放在一个Category中管理,更清晰,就像苹果自身的代码那样,你跳进UIViewController中看看,虽然是一个文件,但是不同功能的实现基本上都是在不同的Category中的,这给我们一个思路,如果一个VC交互复杂、UI上又很多button有很多跳转,我们完全可以用这种方式把耦合性地的部分抽离出来,或把相同功能或业务的部分抽离出来,独立封装成类,这样就可以避免几千行代码的超级VC类的出现,当大家在争着解决臃肿VC的问题而提出的各种五花八门的设计模式的时候,我想这也是一个不错的解决方案(以后会对MVC、MVP、MVVM、MVCS等各种模式提出一些自己的看法)。说到解决方案,如果有看过《Objective-C编程之道——iOS设计模式解析》这本书的朋友会知道,里面为了解决页面跳转混乱、交互复杂的情况引入了中介者模式,个人认为,充当终结者最好是一个NSObject类的子类,而xib的这种用法是中介者模式的一个很好的应用。

总结

xib给了我很大的便利,学习的过程中也给了我很多惊喜,这些高冷用法都是我在学习过程中不断总结出来的,希望大家学习完了之后和我一样,即提高了开发效率,同时学习的过程也令你愉悦。

欢迎大家和我交流沟通,若文章中有错误和纰漏,恳请指正,谢谢。

相关文章

  • 一天一点xib:8高冷的xib

    引言 学到这里,xib给我带来的帮助已经很大了,最大的莫过于UI控件的创建、属性的赋值再也不用写代码,就UI开发来...

  • IOS启动图设置

    iOS8+走LaunchScreen.xib,之前的用LaunchImage。 LaunchScreen.xib丢...

  • Xcode8.0适配

    XIB和Storeboard适配 在Xcode8之前,创建一个XIB或SB文件,都是一个600*600的方块XIB...

  • 低版本的xcode打开xcode8上的xib错误

    XIB和Storeboard适配在Xcode8之前,创建一个XIB或SB文件,都是一个600*600的方块XIB文...

  • WKWebView

    注意点: WKWebView只支持iOS8以上且不支持xib,切勿使用xib进行拖拽 WKWebview 优势: ...

  • tableViewCell相关方法

    用XIB创建tableViewCell的方法 创建方法 创建附带xib的UITableViewCell,在xib上...

  • 关于xcode xib新建button的坑

    非常久没有使用过xib了,今天改了一点小东西,原来是用xib做的,就直接在xib改了只是加了一个button,bu...

  • swift3.0在ios8关联的xib中的控件为nil

    ios8.xController关联xib,需要加上 不然,当点击关联到xib的contro会奔溃,你打断点调试会...

  • xib 约束进阶

    在上一节Xib 约束中,我们介绍了xib 的一些简单用法,今日,我们来看一下xib 复杂一点的知识,在实际开发过程...

  • iOS collectionView XIB 非XIB 随笔

    XIB 非XIB 设置每个cell的大小

网友评论

  • 跳跳虾:xib中一定要添加约束吗?由于之前很少使用xib,最近我刚接手的一个项目,里面基本上都是xib,但是xib里面没有对子控件添加约束,在使用的时候只对整体的view设置了frame,这样是不是算没有适配啊,不是很明白:sob:
  • My少了不少:在tableView的cell里面放collectionView加约束之后为什么不显示?无法得到collectionView的高度
  • ZackLi:亮哥你好,想问你你个问题。我在表格的头视图放了一个图片然后添加了个手势之后连线到VC里点击事件没反应是怎么回事,换成Button可以为什么?
    二亮子:@Kun_Frank_Lee 抱歉才看到,我们加了微信来吧,现在应该搞定了吧:smile:
  • 096438c77112:亮哥,大赞!看了对XIB瞬间改变看法,能写点xib中的First Responder方面的用法吗?
  • 空中舞者VC:老铁,一年过后你这文章也不过时啊!
  • Azzan:好厉害啊,很多方法都是第一次看到,果然高冷,谢谢分享
  • 0271fb6f797c:能给讲一下xib中再使用xib怎么做吗?
  • Mr鹏先生:请问下使用XIB是否占用大量内存?
  • ChiwaiSam:非常感谢分享,学到不少。
    试了OBJC中IBInspectable修饰枚举没法在IB中显示,有办法显示吗?
  • MoMo鲸:关联NSObject这个方法 亮哥能写一个demo么?和代理做一下对比。
    MoMo鲸:@MoMo鲸 我感觉代理能做到的关联NSObject这个方法应该做不到吧
  • e42ae40f7a74:嗯 斯坦福大学的课程 也是这样教学生的
  • 杂食:我擦,半夜看到,太有用了
  • ddaa8dae50b0:用storyboard的runtime attributes设置的属性有时候会没有效果, 运行时也不崩溃 不知道为什么, 用同样的代码设置倒没问题
    sunlin1234:@二亮子 在拖控件的时候有没有什么技巧,比如上下有两层,上边一层有两个view,下边有三个view,这样的怎么布局才不会乱,我布局总是会错乱,头疼死了
    二亮子:@Ian_He 看评论,评论中有讨论过这个问题。
  • 4fcf0567a598:你是想说这样就不用代理或者通知了,可以拖拖拖,拖走鱼尾纹吗?但这样并不是很好的设计模式啊?代码很难维护的,别人看也不好理解
    二亮子:@大巴黎在广州 的确是难维护,算一个缺点,除非大家对xib都了解,那样就有优势了。
  • 4fcf0567a598:还是没弄明白你在IB中添加一个object并把class设置为Person,这样就可以把button和Person类建立联系,但是这又能怎样呢?Person是model,IB和model建立联系没什么意义啊,可否详细解释下这种高冷的实际用处?
    4fcf0567a598:@二亮子 理解的,但是这样会破坏某些xib本身的结构,不过在实际开发中,我们经常甚至会下意识的试图让我们的xib或者view可以复用,但真正能复用到的寥寥无几.
    不过你说的瘦身VC的问题,确实存在,但我仍然不觉得通过连接多个处理对象这种瘦身方式比较好. 你是如何研究到这些高冷的用法的呢?
    二亮子:@大巴黎在广州 它的意义在于,通常VC与xib文件建立关系(一般是file's owner的关系)之后,事件回调由VC处理,如果VC很臃肿,要重构,一般会在VC中弄一个对象,专门处理一些类似事件(有人会把tableView的delegate、datasource事件放在一个NSObject对象里来处理),这样如果xib的交互回调需要在VC中的是一个属性对象中处理的话,事件就不需要传递了,不知道解释清楚了没有,可能还有其他更巧妙的用法,主要意思是可以由之前连接两个对象,变成了连接三个对象,说的不是很明白,你在理解理解吧。
  • UItachi:拖拽NSObject是Cocoa开发的常用技能。
    UItachi:@shenzhenboy 搜索Cocoa开发就有很多结果。
    二亮子:@UItachi 你是说Mac开发?抱歉,没弄过。
    shenzhenboy:@UItachi 能推荐下 相关的文章学习下吗 谢谢。 :smiley:
  • 348bfbe0e20a:其他用法以前也知道了,这次对object的用法很感兴趣。这种用法的应用实例,应该对自定义tableviewcell 上面的各种控件有很大的意义,之前做动态点赞这种,都习惯用block回调来处理,希望作者能给个应用场景的介绍。
    二亮子:@vayne_lee 回复你下面的问题中给了一个应用场景。
  • August24:亮哥,关联NSObject类真的好赞!
  • 一悻:楼主,我在SB中放了个button在User Define Runtime Attribute设置了文中所设置的key value运行为什么没效果呢?
    二亮子:@一悻 如果你遇到的问题和我的不一样,再沟通。
    二亮子:@一悻 第二个原因xib的问题,我这里也遇到了,估计咱俩遇到的应该是相同的问题,我这里设置圆角是可以的,估计你的也应该是可以的,就是设置borderColor和borderWidth的时候没有起作用(至少我的是这样),其实原因是borderColor选择颜色的时候没有选择上,但是borderWidth是生效的,如果你的情况和我的一样,你就用代码设置borderColor,你会发现borderWidth是起作用的。
    二亮子:@一悻 有两个原因:1可能你没有设置上,因为如果你在Key Path里填写了相应的属性,但是并没有按回车而是直接选择Type或Value的话有可能Key Path的属性就没有设置上去,说以你先检查一下Key Path上的属性值是不是你设置的值,如果没有设置成功它会显示keyPath
  • 伤心小剑:拖object这个真是惊艳.
    二亮子:@伤心小剑 😊感谢
    伤心小剑:@二亮子 :blush:感恩
    二亮子:@伤心小剑 还有比这个更惊艳的,会有第10篇,里面会详细介绍,多谢支持。
  • 小兵快跑:亮哥厉害 :fist:
    二亮子:@小兵快跑 ?
  • d8a3e6cf6a08:自认为对xib了解的还算可以,但是看了这篇以后,收货颇多.特别是继承NSobject的xib,必须给作者大写的赞. :+1:
  • c30ec7c7d234:这边文章修改了我对xib的偏见, 还是自己水平不到家啊
    c30ec7c7d234: @二亮子 会的,
    二亮子:@SuperHuihui123 希望你以后能喜欢上xib,提高开发效率
  • Kevinz:看来对xib理解太少了,目前的项目也是半代码半xib ,以后逐渐往SB上靠拢..
    Kevinz:@二亮子 的确, :smile: 感谢LZ分享的技术精髓。
    二亮子:@Kevinz 嗯,作为程序员我们要拥抱变化,追求效率,这是我们的精神所在。
  • qiongyong:好厉害!一直不知道xib还有这么多的功能!
    二亮子:@qiongyong 是啊,如果xib再不强大的话,iOS的布局就落后Android太多了,xib学习是一个长期积累的过程。

本文标题:一天一点xib:8高冷的xib

本文链接:https://www.haomeiwen.com/subject/udolkttx.html