Add closure to extension within swift
主要是利用objc_setAssociatedObject
将closure添加到实例中去,先看看该方法在Objective-c
和swift
中的声明:
Objective-C
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
swift:
public func objc_setAssociatedObject(object: AnyObject!, _ key: UnsafePointer<Void>, _ value: AnyObject!, _ policy: objc_AssociationPolicy)
主要是参数value
的类型,分别是id
和AnyObject
,在Objective-C
中,系统会自动将Block转化id
类型,正常使用,而在swift
里则会提示形如下面的错误信息:
实例代码:
typealias TestClosureType = ()->()
var testClosure: TestClosureType
objc_setAssociatedObject(self, "Test Block", testClosure, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
错误信息提示如下:
Cannot convert value of type 'TestClosureType' (aka '()->()') to expected argument type 'AnyObject!'
原因很清晰,类型不符合,只需要将closure转成AnyObject类型即可,借助于:
public func unsafeBitCast<T, U>(x: T, _: U.Type) -> U
可以将 closure转成AnyObject
类型,只是我们还需要修改点东西,修改之后的结果如下:
typealias TestClosureType = @convention(block)()->()
var testClosure: TestClosureType
objc_setAssociatedObject(self, "Test Block", unsafeBitCast(testClosure, AnyObject.self), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
取出来的时候再转回去,方法如下:
let completionBlock = unsafeBitCast(objc_getAssociatedObject(self, "Test Block"), TestClosureType.self)
使用这个方法,主要是想偷懒,当然定义代理啊通知啊等等都可以解决问题,另当别论。