组件之间进行属性传值的时候,如果通过CTMediator来进行block传值,swift和OC间就会出现block的传值类型不一致,导致报错问题。
这里我们可以利用convention 字段来进行相关转换
此特性用于修饰一个函数对象的类型,以指 定其调用约定。Swift一共有三种调用约定:
(1)swift:用于指示该函数对象为一个 Swift函数的引用。这也是Swift编程语言的标准 函数调用约定。
(2)block:用于指示该函数对象与 Objective-C的Block引用相兼容。也就是说,它 是一个与Objective-C中的 id 相兼容的Objective-C对象,该Block对象将其函数调用嵌 入在其对象内。而内部的函数调用则用的是C调用约定。
(3)c:用于指示该函数对象是一个C函数 的引用。也就是说,该函数引用不带任何执行 上下文,并且直接使用C语言函数调用约定。这 意味着此函数对象可以与C语言中的函数指针进 行直接交互。我们在第22章中会做详细介绍。
我们下面来看些简单的例子。
func test() {
var x = 100
/// ref1具有Swift标准函数调用约定,
/// 它可以对一个捕获局部对象的闭包进行引用 let ref1: @convention(swift) (Int) ->
Void = {
(a: Int) -> Void in
x += a }
/// ref2具有block调用约定,
/// 它可以直接与Objective-C中的Block进行交 互,
/// 同时也能作为一个Objective-C的对象进行使用
let ref2: @convention(block) (Int) ->
Void = {
(a: Int) -> Void in
x -= a }
/// ref3具有C函数调用约定,
/// ref3不能引用一个捕获局部对象的闭包,
/// 因为普通的C函数没有自己的执行上下文,
/// 因此无法对局部对象的捕获做任何处理
let ref3: @convention(c) (Int) -> Void =
ref1(10)
ref2(5)
ref3(1)
print("x = \(x)")
}
test()
ok,convention字段介绍完了,我们这里就用到了它的block调用约定
/*
1、 拿到OC传过来的 block 属性
*/
let parBlock = params["block"]
/*
2、 定义对应类型的 block 别名,用 @convention(block) 修饰
@convention(swift) block类型 :声明这是swift block
@convention(block) block类型 :声明这是兼容swift | oc 的 block
@convention(c) block类型 :声明这是c block
BlockType : 别名
((Dictionary<String,Any>) -> Void : 传入swift中的 block 类型
*/
typealias BlockType = @convention(block) (Dictionary<String,Any>) -> Void
/*
3、 获取 parBlock 的内存地址
Unmanaged: 用于传播非托管对象引用的类型(不用ARC)
Unmanaged.passRetained : 如果这个非托管对象的使用全程,能够保障被封装对象一直存活,我们就可以使用 passUnretained 方法,对象的生命周期还归编译器管理
Unmanaged.passUnretained : 如果非托管对象使用周期超过了编译器认为的生命周期,比如超出作用域,编译器自动插入 release 的 ARC 语义,那么这个非托管对象就是一个野指针了,此时我们必须手动 retain 这个对象,也就是使用 passRetained 方法
一旦你手动 retain 了一个对象,就不要忘记 release 掉它,方法就是调用非托管对象的 release 方法,或者用 takeRetainedValue 取出封装的对象,并将其管理权交回 ARC。但注意,一定不要对一个用 passUnretained 构造的非托管对象调用 release 或者 takeRetainedValue,这会导致原来的对象被 release 掉,从而引发异常。
*/
let blockPtr = UnsafeRawPointer(Unmanaged<AnyObject>.passUnretained(parBlock as AnyObject).toOpaque())
/*
4、 根据 3 的内存地址将内存里的内容转为 2 定义的类型
unsafeBitCast(x, to: type) :将x内存地址的内容强转为 type 类型的内容
blockPtr : 地址
BlockType : block 类型
*/
let newBlock = unsafeBitCast(blockPtr, to: BlockType.self)
最后,将我们得到的newBlock赋值给swift中的Block就搞定啦