在程序編寫過程當中,咱們經常須要爲已有的類擴展新的屬性。一般咱們的解決辦法是先聲明一個Key,而後使用objc_getAssociatedObject
和objc_setAssociatedObject
來設置屬性。相對來講比較麻煩,由於擴展屬性的需求比較大,因此筆者對這兩個方法作了一些封裝,減小了不少代碼。
首先咱們來看看封裝後如何使用。swift
extension View:Property{ var margin : Int{ get{ return get0() } set{ set0(newValue)} } }
是否是很是簡單?不過在使用這個Property以前,必定要看清楚注意事項哦。
Property裏面默認封裝了設置三個屬性的方法。
擴展前三個屬性的時候分別是 get0() & set0()、get1() & set1()、get2() & set2()
那麼超過三個屬性應該如何設置呢?數組
var test : String{ get{ return get(&keyPoint) } set{ set(&keyPoint, newValue)} }
也仍是比較簡單的,畢竟爲一個類擴展超過三個以上的屬性的需求仍是比較小的。測試
首先咱們看看,擴展屬性一般使用的代碼指針
struct XKeys { static var common : String = "common" } extension AbstractProtocol{ var common : String{ get{ return objc_getAssociatedObject(self, &XKeys.common) as! String } set{ objc_setAssociatedObject(self, &XKeys.common, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } }
在複製粘貼了屢次這樣的代碼以後,我實在厭倦了這樣擴展屬性的方式,而後開始了本身的封裝。
首先我發現聲明一個Key以後,能夠給多個類共用,沒有任何影響,可是若是同一個類的不一樣屬性,使用了相同的Key,就會有問題了。因此首先要保證同一個類,擴展出來的不一樣屬性的key值必需要不一樣。
因此我想到用一個數組來保存key,不過很惋惜失敗了。code
最開始封裝Property的時候是直接聲明瞭一個類,寫了一些靜態方法。而後在get set中調用。對象
class Property2 { static func get<T : Any>(_ key: UnsafeRawPointer) -> T{ return objc_getAssociatedObject(self, key) as! T } static func set<T : Any>(_ key: UnsafeRawPointer,_ newValue : T) { objc_setAssociatedObject(self, key, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } }
不過測試過程當中發現一些問題,這個self實際應該使用被擴展的對象的類的self,因此通過修改後,代碼以下:繼承
class Property2 { static func get<T : Any>(_ o : Any, _ key: UnsafeRawPointer) -> T{ return objc_getAssociatedObject(o, key) as! T } static func set<T : Any>(_ o : Any, _ key: UnsafeRawPointer,_ newValue : T) { objc_setAssociatedObject(o, key, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } }
調用的時候:ci
var common : String{ get{ return Property2.get(self, &XKeys.common) } set{ Property2.set(self, &XKeys.common, newValue) } }
感受封裝了跟沒封裝基本差很少啊。
有沒有辦法能省略Property和self呢,因而我想到了Protocol,而後讓類去繼承個人Property,這樣就能夠省略掉這兩項了。不過Key仍是要傳遞,因此我默認聲明瞭三個key,再提供一個須要傳遞key的方法。最後封裝好的代碼爲:get
// Property.swift // // Created by Fancy on 26/1/18. // Copyright © 2018年 Artifex Software, Inc. All rights reserved. import UIKit struct PropertyKey{ static var key0 : Void? static var key1 : Void? static var key2 : Void? } protocol Property{} extension Property{ func get<T : Any>(_ key: UnsafeRawPointer) -> T{ return objc_getAssociatedObject(self, key) as! T } func set<T : Any>(_ key: UnsafeRawPointer,_ newValue : T) { objc_setAssociatedObject(self, key, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } func get0<T : Any>() -> T{ return objc_getAssociatedObject(self, &PropertyKey.key0) as! T } func set0<T : Any>(_ newValue : T) { objc_setAssociatedObject(self, &PropertyKey.key0, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } func get1<T : Any>() -> T{ return objc_getAssociatedObject(self, &PropertyKey.key1) as! T } func set1<T : Any>(_ newValue : T) { objc_setAssociatedObject(self, &PropertyKey.key1, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } func get2<T : Any>() -> T{ return objc_getAssociatedObject(self, &PropertyKey.key2) as! T } func set2<T : Any>(_ newValue : T) { objc_setAssociatedObject(self, &PropertyKey.key2, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } }
整個封裝過程沒有什麼高科技含量的操做,寫文章作點記錄,但願能給到須要的人幫助。it