我最近自學(xué)Swift3.0惭婿,由于之前沒學(xué)過Swift幕与,只能將OC的代碼“翻譯”成Swift彼妻,在此過程慢慢學(xué)習(xí)Swift语卤,Swift3.0的資料少宵喂,遇到了不少坑揍堕,今天就介紹一個窝剖。
在OC里面沃饶,咱給分類添加屬性是這么寫的棠隐,即使用Runtime
中的objc_setAssociatedObject
和objc_getAssociatedObject
- (void)setQuickTapEnable:(BOOL)quickTapEnable{
objc_setAssociatedObject(self, JKSecurityButtonQuickTapEnableKey, @(quickTapEnable), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)quickTapEnable{
return [objc_getAssociatedObject(self, JKSecurityButtonQuickTapEnableKey) boolValue];
}
這次咱用Swift3.0給ViewController的Extension(相當(dāng)于OC里面的Category)添加一個屬性JKPro石抡,賦值后再取出來打印,練練手助泽。
ViewControll類文件的代碼:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.jkPro = "通過類別拓展的屬性"
NSLog(self.jkPro!)
print("標(biāo)記")
}
}
ViewControll Extension文件的代碼
extension ViewController {
// 平常寫法[不推薦]
var jkPro: String? {
set {
objc_setAssociatedObject(self, "key", newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
}
get {
return objc_getAssociatedObject(self, "key") as? String
}
}
}
你覺得有問題嗎啰扛? 我告訴你嚎京,有
運行多次后會出現(xiàn)隨機性的崩潰,也就是說基本上能正常運行和打印結(jié)果隐解,但是偶爾會出現(xiàn)崩潰鞍帝,我也一直沒找到根本原因,不過找到了解決方案煞茫。
崩潰后會進入下面的界面:
運行10次左右會隨機出現(xiàn)崩潰帕涌,提示
fatal error: unexpectedly found nil while unwrapping an Optional value
,也就是中間出現(xiàn)了nil再看看崩潰點的代碼: 解包出錯溜嗜!
那就從源頭找問題宵膨,后面改成下面寫法來測試崩潰,運行多次后發(fā)現(xiàn)是
objc_getAssociatedObject
返回的值為nil炸宵,導(dǎo)致解包崩潰辟躏。有時正常,有時nil土全,什么鬼??????
再看看objc_setAssociatedObject
函數(shù)方法捎琐,用到了UnsafeRawPointer
類型的參數(shù),沒接觸過裹匙,那就從UnsafeRawPointer
入手
public func objc_setAssociatedObject(_ object: Any!, _ key: UnsafeRawPointer!, _ value: Any!, _ policy: objc_AssociationPolicy)
通常咱用字符串來命名以及區(qū)分Key值瑞凑,然而UnsafeRawPointer
并沒有String
參數(shù)的init方法,倒是有個Int
參數(shù)的init方法概页,但是咱不能用數(shù)字做Key吧籽御,隊友一看代碼能知道啥意思嗎?慶幸的是String
的hashValue (哈希值)
可以返回Int值惰匙,而字符串的哈希值和字符串是一一對應(yīng)的技掏,測試多次都沒出現(xiàn)崩潰,完美项鬼。
下面就是一種解決方案哑梳,應(yīng)該還有其他的,只是等著大家去發(fā)現(xiàn)
/// 推薦寫法
var jkPro: String? {
set {
let key: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "key".hashValue)
objc_setAssociatedObject(self, key, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
}
get {
let key: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "key".hashValue)
let obj: String? = objc_getAssociatedObject(self, key) as? String
return obj
}
}
-------------------------繼續(xù)改進-------------------------
之前崩潰原因已找到绘盟,之所以出現(xiàn)nil鸠真,是因為2次使用的Key
內(nèi)存地址不一樣導(dǎo)致的,即取值和設(shè)值的Key內(nèi)存地址不一樣導(dǎo)致取出nil龄毡,解包nil崩潰吠卷。
同一字符串的哈希值是一樣的,所以方向是對的沦零,于是下午繼續(xù)優(yōu)化了下撤嫩。使用結(jié)構(gòu)體struct
作為容器聲明不同的Key,以后改也只要一個改地方就行蠢终,便于管理序攘,而且相比上午的寫法代碼量更少茴她,更簡潔。
如果有其他的思路程奠,歡迎一起討論丈牢。
// 改進寫法【推薦】
struct RuntimeKey {
static let jkKey = UnsafeRawPointer.init(bitPattern: "JKKey".hashValue)
/// ...其他Key聲明
}
var jkPro: String? {
set {
objc_setAssociatedObject(self, ViewController.RuntimeKey.jkKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
}
get {
return objc_getAssociatedObject(self, ViewController.RuntimeKey.jkKey) as? String
}
}
我所有Swift3.0練習(xí)Demo都放到了Github上,并且在不斷更新瞄沙。
Swift3.0朝圣之路-全集地址
- Swift3.0閉包的使用詳解,簡單封裝GET/POST網(wǎng)絡(luò)請求
- WKWebView的使用詳解己沛,包括JS交互
- 原來MapKit的簡單使用,包括定位+地圖+地理編碼
- OC+Swift混編,介紹高德地圖SDK的簡單使用距境,包括定位+地圖+POI搜索+導(dǎo)航+UISearchController使用
- 協(xié)議代理的基礎(chǔ)用法
- 分類/類別的使用和封裝
- 【Then協(xié)議庫】-眼前一亮的初始化方式
- 使用Runtime在分類Extension中添加屬性
- 封裝UIAlertController
- 自定義相冊【尚未完成】
- 用原生框架掃描申尼、識別二維碼圖片,生成黑白色垫桂、彩色二維碼圖片