#
我最近自学Swift3.0,由于之前没学过Swift,只能将OC的代码“翻译”成Swift,在此过程慢慢学习Swift,Swift3.0的资料少,遇到了不少坑,今天就介绍一个。
在OC里面,咱给分类添加属性是这么写的,即使用Runtime
中的objc_setAssociatedObject
和objc_getAssociatedObject
1 | - (void)setQuickTapEnable:(BOOL)quickTapEnable{ |
这次咱用Swift3.0给ViewController的Extension(相当于OC里面的Category)添加一个属性JKPro,赋值后再取出来打印,练练手。
ViewControll类文件的代码:
1 | class ViewController: UIViewController { |
ViewControll Extension文件的代码
1 | extension ViewController { |
你觉得有问题吗? 我告诉你,有
运行多次后会出现随机性的崩溃,也就是说基本上能正常运行和打印结果,但是偶尔会出现崩溃,我也一直没找到根本原因,不过找到了解决方案。
崩溃后会进入下面的界面:
常规写法崩溃
运行10次左右会随机出现崩溃,提示
1 | fatal error: unexpectedly found nil while unwrapping an Optional value |
,也就是中间出现了nil
再看看崩溃点的代码: 解包出错!
常规写法崩溃信息
那就从源头找问题,后面改成下面写法来测试崩溃,运行多次后发现是
1 | objc_getAssociatedObject |
返回的值为nil,导致解包崩溃。
有时正常,有时nil,什么鬼❓❓❓❓❓❓
常规写法崩溃信息
再看看objc_setAssociatedObject
函数方法,用到了UnsafeRawPointer
类型的参数,没接触过,那就从UnsafeRawPointer
入手
1 | public func objc_setAssociatedObject(_ object: Any!, _ key: UnsafeRawPointer!, _ value: Any!, _ policy: objc_AssociationPolicy) |
通常咱用字符串来命名以及区分Key值,然而UnsafeRawPointer
并没有String
参数的init方法,倒是有个Int
参数的init方法,但是咱不能用数字做Key吧,队友一看代码能知道啥意思吗?庆幸的是String
的hashValue (哈希值)
可以返回Int值,而字符串的哈希值和字符串是一一对应的,测试多次都没出现崩溃,完美。
下面就是一种解决方案,应该还有其他的,只是等着大家去发现
1 | /// 推荐写法 |
————————-继续改进————————-
之前崩溃原因已找到,之所以出现nil,是因为2次使用的Key
内存地址不一样导致的,即取值和设值的Key内存地址不一样导致取出nil,解包nil崩溃。
同一字符串的哈希值是一样的,所以方向是对的,于是下午继续优化了下。使用结构体struct
作为容器声明不同的Key,以后改也只要一个改地方就行,便于管理,而且相比上午的写法代码量更少,更简洁。
如果有其他的思路,欢迎一起讨论。
1 | // 改进写法【推荐】 |
我所有Swift3.0练习Demo都放到了Github上,并且在不断更新。
转:Swift3.0朝圣之路-全集地址
>