对于 Framework 不支持@ibdesignable研究

写出这一篇文章之前,我搜索了很多的资料。牵扯出来的东西实在是太多,很多我没法理解其中的原理,可能我看的不详细,并且不需要去知道牵扯出来原理,我只是想解决办法而已。

最近写了一个控件,是为了做共享车位项目的一个选择控件。在最后的版本我加了@IBDesignable@IBInspectable两个关键词用于支持 Xib 的及时预览和设置。

最近在想使用 Carthage 打包成 Framework 之后,放在 Cocoapods 进行依赖,会简单很多。

但是我们的控件在 Xib 不能及时的预览,不能及时的渲染。我们的代码可是在自己的例子里面经过测试的!

我们不但在 Swift 的例子里面测试通过,而且还在 OC 的例子里面测试通过。但是我们托管在 Cocoapods 之后,竟然无法通过了?

当时一时不明白什么原因,恰巧看到群里面有人分享说 Xcode9之前 Swift 不支持静态库。

https://zhuanlan.zhihu.com/p/32178522?group_id=926848741735350272

当时就好奇的搜索一下什么是静态库和动态库。

https://www.jianshu.com/p/42891fb90304

下面我就说一下我的理解,简单说一下所谓的动态库是可以代码共享供其他程序使用的,比如系统的 UIKit.framework Foundation.framework 都是存在于 iOS系统里面。

不同的 APP 都是依赖于 iOS 系统里面这些动态库,这就所谓我们的安装包会变小。

所谓的静态库就是复制一份代码到我们的 APP 里面,比如其他第三方打包号的 Framework,比如 Cocoapods 托管的。

说到这里,我们已经注意到为什么自己打包出来的.Framework 是赋值代码到我们 APP 是属于静态库,为什么系统的.framework 是属于共享代码属于动态库呢?

我们自己口中所谓的创建动态库和静态库究竟是怎么的一回事呢?我们看一下下面的图。

0E17A928-4701-464E-9DCF-67C76129E07B

这就是我理解的图,所以对于 Framework 有三种

  1. 存在于 iOS 系统供其他 APP 共享代码使用的真正动态库
  2. 存在于 APP 沙盒下面供扩展程序和主程序使用的伪动态库
  3. 复制代码只供主程序使用的静态库

搜索了静态库和动态库的区别之后,对比自己测试的 Demo 和自己真正用的例子发现。

自己的 Demo 都在一个工程,属于伪动态的库。但是自己打包成 Framework 不管是拖拽还是使用 Cocoapods 都已经变成了静态库了。所以应该是这个原因导致的。

后来,我就直接让代码使用 Cocoapods 进行托管。但是发现还是不行,当时就百度了

Cocoapods not support @IBDesignable

虽然这个问题在 Cocoapods 的问题列表出现很多次,但是官方给的回复是我们的库有问题和 Cocoapods 没有什么关系。

最后我再次修改了搜索的关键词

swift @IBDesignable framework not work in xib

这次搜索果然有收获,并且大概知道了解决的办法。

https://github.com/Carthage/Carthage/issues/335

http://stackoverflow.com/a/39999914/760435

一个采纳的建议为使用者自己创建子类或者分类,重写@IBDesignable标识符。

我试了一些,是可以正常的渲染出来,但是属性还是无法在 Xib 设置。

此时此刻,我大概明白了出不来造成的原因是什么。是因为 Swift 文件会被自动 Generated Interface 头文件的时候

@IBDesignable@IBDesignable关键词不会被自动转换为 OC 的宏IB_DESIGNABLEIBInspectable

因为打包成 Framework 会被自动转换为 OC 里面的头文件,因此缺少标识的宏自然无法在 Xib 进行渲染和识别。

三种方法可以解决

1.代码开源使用 Cocoapods

使用 Cocoapods 直接托管我们的源文件,这样就形成了我们所说的伪动态库。

只有在运行的时候才被编译成库,这样 Xib 就可以在编译的时候看到源文件,识别出@IBDesignable@IBDesignable关键词。

2. 打包成 Framework

如果想使用 Framework 的话,比如使用 Carthage 之类。自动生成的头文件自然是无法支持的。

我们想要支持的话就必须是把我们声明@IBDesignable@IBDesignable关键词的文件暴露在 public header 列表之下。

34C8DA6D-B199-4B42-A5FD-7043D407BD8F

那么打包出来的 Framework ,程序也可以看到我们的源文件,自然而然的就支持 Xib 渲染了。

3. 打包成 Framework 不想让别人知道核心代码

这个就有点难度了,毕竟你不想让别人知道核心代码。又要让自己的库支持Xib的话。

你就必须参考上面2所说的,做一个可以暴露源码的文件,把@IBDesignable@IBDesignable关键词写在这个文件里面。之后再把设置的属性赋值给核心库,这样核心的类会自动生成。

类似下面

0095545E-CCE3-47D7-89BF-439A7003A8F3

这样只不过提供库作者麻烦一些,谁让自己不愿意开源呢?

据说 Framework 不支持@IBDesignable是苹果的一个 BUG,至今还没有修复

https://openradar.appspot.com/23114017