Swift 使用runtime给extension添加属性

最近使用swift写新项目,也算是试水,虽然现在swift算是推广起来了,很多大厂小公司的新项目都是swift,但是还是不少坑,这两天写一个waveView就遇到了个这个问题


一般再OC中使用runtime给分类添加属性是这个样子的objc_setAssociatedObjectobjc_getAssociatedObject

1
2
3
4
5
6
7
- (void)setSomeProperty:(NSString *)someProperty{
objc_setAssociatedObject(self, Key, @(quickTapEnable), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSString *)someProperty{
return [objc_getAssociatedObject(self, Key) boolValue];
}

看了看之前写过的OC代码,微微一笑,写出了这段代码

1
2
3
4
5
6
7
8
var refreshView : WaveView{
set{
objc_setAssociatedObject(self, "key", newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
}
get{
return objc_getAssociatedObject(self, "key") as! WaveView
}
}

1.png

然后用了一下这个这几行检验一下,果然没存进去。。。

我们看一下objc_setAssociatedObject的API

1
2
3
4
5
6
7
8
9
10
11
12
13
/** 
* Sets an associated value for a given object using a given key and association policy.
*
* @param object The source object for the association.
* @param key The key for the association.
* @param value The value to associate with the key key for object. Pass nil to clear an existing association.
* @param policy The policy for the association. For possible values, see “Associative Object Behaviors.”
*
* @see objc_setAssociatedObject
* @see objc_removeAssociatedObjects
*/
@available(iOS 3.1, *)
public func objc_setAssociatedObject(_ object: Any!, _ key: UnsafeRawPointer!, _ value: Any!, _ policy: objc_AssociationPolicy)

第二个参数是UnsafeRawPointer结构体指针类型,Swift并不推荐对指针进行直接操作, 但仍提供了几种可以直接操作内存的指针类型,在Swift中无类型的指针,原始内存可以用UnsafeRawPointerUnsafeMutableRawPointer来表示

我们看一下UnsafeRawPointer的构造函数

1
2
3
4
5
6
7
8
9
/// Converts a pattern of bits to an `UnsafeRawPointer`.
///
/// Returns `nil` if `bitPattern` is zero.
public init?(bitPattern: Int)

/// Converts a pattern of bits to an `UnsafeRawPointer`.
///
/// Returns `nil` if `bitPattern` is zero.
public init?(bitPattern: UInt)

要想通过字符串生成意义对应的Int值,我们可以使用

"key".hashValue的形式将字符串生成哈希值来返回Int

1
2
3
4
5
6
7
8
9
10
var refreshView : WaveView? {
set{
let key: UnsafeRawPointer! = UnsafeRawPointer(bitPattern: "key".hashValue)
objc_setAssociatedObject(self, key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get{
let key: UnsafeRawPointer! = UnsafeRawPointer(bitPattern: "key".hashValue)
return objc_getAssociatedObject(self, key) as? WaveView
}
}

2.png

这种方法完美解决了解包失败


因为是经常使用的key值,我们应该一次定义多次调用,避免这样重复写好多次,如同在配置文件里面定义全局通知的标识符一样

1
let key = UnsafeRawPointer(bitPattern: "key".hashValue)

希望这篇文章可以帮到大家