0
点赞
收藏
分享

微信扫一扫

【OC/Swift混编】接口中数据类型的建议(三):类型转换底层实现原理

村里搬砖的月野兔 2022-01-30 阅读 174

本文目录

一、前言

本文通过反汇编伪代码+Swift源码+Swift的Foundation源码来分析OC与Swift之间数据类型转换的底层实现,结论如下:

二、OC到Swift类型转换底层实现结论

对于NSStringNSArrayNSDictionary等这类不可变类型的变量,将其转换为Swift中相对应的类型时,是调用由Foundation框架对应数据类型extension中所提供的_unconditionallyBridgeFromObjectiveC函数。

例如下面的代码:

let ocDict:NSDictionary = NSDictionary.init(dictionary:["strKey":"strValue","boolKey":true,"dictKey":["key":"value"]])
let swDict = ocDict

其本质为:

let ocDict:NSDictionary = NSDictionary.init(dictionary: ["strKey":"strValue","boolKey":true])
let swDict:Dictionary<String,Any> = Dictionary<String,Any>._unconditionallyBridgeFromObjectiveC(ocDict)

对于NSMutableStringNSMutableArrayNSMutableDictionary等可变类型或者其它自定义类型变量,在转换为swift多对应的对象时经历了三个步骤:(以NSMutableDictionary转换为swift中的Dictionary为例)
1.调用swift_dynamicCastObjCClassUnconditional,将NSMutableDictionary强制转换为NSDictionary类型。
2.调用_swift_instantiateConcreteTypeFromMangledName,获取Swift的Dictionary元类
3.调用Swift._forceBridgeFromObjectiveC_bridgeable,将NSDictionary转换为Swift的Dictionary(本质仍然是调用Foundation框架中其对应类型的extension提供的_unconditionallyBridgeFromObjectiveC方法)

三、Swift到OC类型转换底层实现结论

通过Foundation框架中其对应类型extension提供的_bridgeToObjectiveC方法将swift对象转换为OC对象。

let swDict:[String:Any] = ["strKey":"strValue","boolKey":true,"dictKey":["key":"value"]]
let ocDict:NSDictionary = swDict as NSDictionary

本质

let swDict:[String:Any] = ["strKey":"strValue","boolKey":true,"dictKey":["key":"value"]]
let ocDict:NSDictionary = swDict._bridgeToObjectiveC()

四、工欲善其事,必先利其器

本文分析所用到的工具及源码如下:
反汇编工具:Hopper Disassembler
Swift源码:https://github.com/apple/swift.git
Foundation源码:https://github.com/apple/swift-corelibs-foundation.git

五、分析NSDictionary转换为[String:Any]

testDict1testDict3都是将OC的NSDictionary对象转换为Swift中的Dictionary对象,其反汇编后的伪代码类似,以testDict3方法为例,其反汇编后的伪代码如下:

int _$s9studyObjc9TestSwiftC9testDict333_2F437011BB19CEAD190854F9BDB31C8BLLyyF() {
    type metadata accessor for __C.TestDataModel(0x0, rsi, rdx, rcx);
    rax = __C.TestDataModel.__allocating_init();
    var_70 = rax;
    rax = [rax dict3];
    rax = [rax retain];
    rdx = *type metadata for Any;
    var_20 = static (rax, *type metadata for Swift.String, rdx + 0x8, *protocol witness table for Swift.String : Swift.Hashable in Swift);
    [var_70 release];
    [rax release];
    var_50 = Swift._allocateUninitializedArray<A>(0x1, rdx + 0x8);
    swift_bridgeObjectRetain(var_20);
    *(rdx + 0x20) = ___swift_instantiateConcreteTypeFromMangledName(_$sSDySSypGMD);
    *(rdx + 0x8) = var_20;
    var_28 = Swift._finalizeUninitializedArray<A>(var_50, rdx + 0x8);
    Swift.print(var_28, default argument 1 of Swift.print(), rdx + 0x8, default argument 2 of Swift.print(), rdx + 0x8);
    swift_bridgeObjectRelease(rdx + 0x8);
    swift_bridgeObjectRelease(rdx + 0x8);
    swift_bridgeObjectRelease(var_28);
    rax = swift_bridgeObjectRelease(var_20);
    return rax;
}

我们可以看到,其调用static方法,并将其结果返回给了var_20变量。static方法的伪代码如下:

function $sSD10FoundationE36_unconditionallyBridgeFromObjectiveCySDyxq_GSo12NSDictionaryCSgFZ {
    rax = (*pointer to static (extension in Foundation):Swift.Dictionary._unconditionallyBridgeFromObjectiveC(__C.NSDictionary?) -> [A : B])();
    return rax;
}

从上述代码中我们可以看到,NSDictionary转换为Dictionary<String:Any>本质是调用了Foundtion框架中Dictionary的静态方法_unconditionallyBridgeFromObjectiveC

我们可以从Foundation源码中找到该函数的实现如下:

//swift-corelibs-foundation/Sources/Foundation/Dictionary.swift
static public func _forceBridgeFromObjectiveC(_ source: _ObjectType, result: inout Dictionary?) {
        result = _unconditionallyBridgeFromObjectiveC(source)
}

static public func _unconditionallyBridgeFromObjectiveC(_ source: _ObjectType?) -> Dictionary {
        if let object = source {
            var value: Dictionary<Key, Value>?
            _conditionallyBridgeFromObjectiveC(object, result: &value)
            return value!
        } else {
            return Dictionary<Key, Value>()
        }
}

static public func _conditionallyBridgeFromObjectiveC(_ source: _ObjectType, result: inout Dictionary?) -> Bool {
        var dict = [Key: Value]()
        var failedConversion = false

        if type(of: source) == NSDictionary.self || type(of: source) == NSMutableDictionary.self {
            source.enumerateKeysAndObjects(options: []) { key, value, stop in
                guard let key = key as? Key, let value = value as? Value else {
                    failedConversion = true
                    stop.pointee = true
                    return
                }
                dict[key] = value
            }
        } else if type(of: source) == _NSCFDictionary.self {
            let cf = source._cfObject
            let cnt = CFDictionaryGetCount(cf)

            let keys = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: cnt)
            let values = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: cnt)

            CFDictionaryGetKeysAndValues(cf, keys, values)

            for idx in 0..<cnt {
                let key = __SwiftValue.fetch(nonOptional: unsafeBitCast(keys.advanced(by: idx).pointee!, to: AnyObject.self))
                let value = __SwiftValue.fetch(nonOptional: unsafeBitCast(values.advanced(by: idx).pointee!, to: AnyObject.self))
                guard let k = key as? Key, let v = value as? Value else {
                    failedConversion = true
                    break
                }
                dict[k] = v
            }
            keys.deinitialize(count: cnt)
            values.deinitialize(count: cnt)
            keys.deallocate()
            values.deallocate()
        }
        if !failedConversion {
            result = dict
            return true
        }
        return false
}

从上述代码来看,其本质就是遍历NSDictionary的key和value,重新组合成Swift中Dictionary类型。
testDict1的反汇编代码与testDict3的反汇编代码类似,其调用的核心代码都是:

Swift.Dictionary._unconditionallyBridgeFromObjectiveC

因此,我们可以得到结论:
对于NSDictionary<NSString*,id>转换为Dictionary<String:Any>,其本质都调用了_unconditionallyBridgeFromObjectiveC,都是遍历NSDictionary中的key和value,重新组合成Dictionary类型。

六、分析NSMutableDictionary到Dictionary<String:Any>

testDict2函数反汇编之后的伪代码如下:

int _$s9studyObjc9TestSwiftC9testDict233_2F437011BB19CEAD190854F9BDB31C8BLLyyF() {
    type metadata accessor for __C.TestDataModel(0x0, rsi, rdx, rcx);
    rax = __C.TestDataModel.__allocating_init();
    var_90 = [[rax dict2] retain];
    [rax release];
    var_78 = swift_dynamicCastObjCClassUnconditional(var_90, swift_getInitializedObjCClass(@class(NSDictionary)), 0x0, 0x0, 0x0);
    var_68 = ___swift_instantiateConcreteTypeFromMangledName(_$sSDySSypGMD);
    [var_78 retain];
    Swift._forceBridgeFromObjectiveC_bridgeable<A where A: Swift._ObjectiveCBridgeable>(var_78, var_68, var_68, lazy protocol witness table accessor for type [Swift.String : Any] and conformance [A : B] : Swift._ObjectiveCBridgeable in Foundation());
    [var_78 release];
    [var_78 release];
    var_58 = Swift._allocateUninitializedArray<A>(0x1, *type metadata for Any + 0x8);
    swift_bridgeObjectRetain(var_18);
    *(var_68 + 0x18) = var_68;
    *var_68 = var_18;
    var_30 = Swift._finalizeUninitializedArray<A>(var_58, rsi + 0x8);
    Swift.print(var_30, default argument 1 of Swift.print(), var_68, default argument 2 of Swift.print(), var_68);
    swift_bridgeObjectRelease(var_68);
    swift_bridgeObjectRelease(var_68);
    swift_bridgeObjectRelease(var_30);
    rax = swift_bridgeObjectRelease(var_18);
    return rax;
}

从上述伪代码中,可以总结出来,从NSMutableDictionary<NSString*,id>Dictionary<String:Any>,一共分为三个步骤:
1.调用swift_dynamicCastObjCClassUnconditional,将NSMutableDictionary强制转换为NSDictionary类型。
2.调用_swift_instantiateConcreteTypeFromMangledName,获取Swift的Dictionary元类
3.调用Swift._forceBridgeFromObjectiveC_bridgeable,将NSDictionary转换为Swift的Dictionary

具体的细节可以参考如下信息:

举报

相关推荐

0 条评论