美文网首页
Swift 和OC的blcok属性不一致问题

Swift 和OC的blcok属性不一致问题

作者: 流云_henry | 来源:发表于2021-10-26 15:20 被阅读0次

    组件之间进行属性传值的时候,如果通过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就搞定啦

    相关文章

      网友评论

          本文标题:Swift 和OC的blcok属性不一致问题

          本文链接:https://www.haomeiwen.com/subject/dhfyaltx.html