几乎在我们所有的iOS App 项目中我们都为了开发方便,为了Deadline都会在我们的项目中使用一些别人造好的轮子。使用这些轮子一般都很简单,但是我们也要好好学习别人造的这些轮子背后的原因,大神们为什么要这么造?阅读大神们的代码来理解他们的造这些轮子的思想与方法对我们能力的提示也会有很大帮助。这篇文章就简单写一下我阅读SDAutoLayout这个自动布局开源库的源码之后的理解吧。
直接上代码:
UILabel *titleLabel = [[UILabel alloc]init];
titleLabel.text = @"test string";
[self.view addSubview:titleLabel];
titleLabel.sd_layout
.leftSpaceToView(self.view,20)
.topSpaceToView(self.view,100)
.rightSpaceToView(self.view,20)
.heightIs(20);
上面这段代码就是就是用SDAutoLayout对一个Label进行适配不同屏幕的简单例子。很简单、很暴力,并且是我们用起来很方便的链式调用方式。我们进行断点调试进入到SDAutoLayout的源代码中。
首先执行sd_layout这个方法,这个方法的作用就是创建并初始化一些参数返回SDAutoLayoutModel这个对象的实例,然后就真正的开始进行自动布局的代码。
接下来查看leftSpaceToView()这个方法会看到这个方法是一个懒加载的方法,在懒加载的方法中会执行这个方法marginToViewblockWithKey,这个方法很有意思,其中的key与SDAutoLayoutModel的私有属性left相同。
进入到这个方法就可以看到返回值为一个block,而且在block中会通过KVC的方式设置SDAutoLayoutModel实例的属性(与这个方法的key名字相同)的value为SDAutoLayoutModelItem的实例对象,仔细发现SDAutoLayoutModel实例的私有属性的类型就是SDAutoLayoutModelItem。咋下面中我们也可到作者提供了这些属性的set方法,我们刚学KVC的时候大家都知道,KVC的机制是首先从调用setter方法,找不到setter方法就查找对象是否存在属性等的直到找不到任何相关的就会报错。我们查看这些setter方法就可以看到这写setter方法就是设置当前view的frame的属性。
到这个时候我们就明白了这个第三方库的核心还是设置view的frame来进行适配。但是还有一点不同,在这个方法中还使用了黑魔法(runtime)Method Swizzing,在load方法中替换了layoutSubViews。因为在iOS中设置view的frame就会自动调用layoutSubViews这个方法,下面是会调用layoutSubViews方法的情况:
1. 直接调用setLayoutSubviews。(这个在上面苹果官方文档里有说明)
2. addSubview的时候。
3. 当view的frame发生改变的时候。
4. 滑动UIScrollView的时候。
5. 旋转Screen会触发父UIView上的layoutSubviews事件。
6. 改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件。
在替换的sd_layoutSubviews中执行了sd_layoutSubviewsHandle这个方法,这个方法就是针对不同的view及情况进行宽度、高度等属性进行计算,并且会缓存tableViewCell的高度等。
接下来的topSpaceToView、rightSpaceToView、heightIs等方法跟leftSpaceToView方法类似,大同小异,我就不做一一解释了。
总结一下这个开源库的原理就是通过KVC、链式调用、Runtime的Method Swizzing等技术创造的轮子。这个库还提供了一些其他功能,我们平时开发使用起来还是很简单方便的,能很大程度上提高我们的开发效率。工作之余可以多学学作者怎么使用这些技术创造轮子以及为什么这样写也是一件很有趣的事情。