本文目录
- 一、前言
- 二、OC到Swift类型转换底层实现结论
- 三、Swift到OC类型转换底层实现结论
- 四、工欲善其事,必先利其器
- 五、分析NSDictionary转换为[String:Any]
- 六、分析NSMutableDictionary到Dictionary\
一、前言
本文通过反汇编伪代码+Swift源码+Swift的Foundation源码来分析OC与Swift之间数据类型转换的底层实现,结论如下:
二、OC到Swift类型转换底层实现结论
对于NSString
,NSArray
,NSDictionary
等这类不可变类型的变量,将其转换为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)
对于NSMutableString
,NSMutableArray
,NSMutableDictionary
等可变类型或者其它自定义类型变量,在转换为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]
testDict1
和testDict3
都是将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
。
具体的细节可以参考如下信息:
略