在程序编写过程当中,咱们经常须要为已有的类扩展新的属性。一般咱们的解决办法是先声明一个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