我们知道在Swift中,可以在NSArray与Array之间做无缝的转换,如下所示:
let mobile = ["iPhone", "Nokia", "小米Note"]let mobile1 = (mobile as NSArray).objectAtIndex(1)print(mobile1)let animalArray = NSArray(objects: "lion", "tiger", "monkey")var animalCount = (animalArray as Array).countprint(animalCount)// 输出// "Nokia"// ["lion", "tiger", "monkey"]编译器会为了我们完成所有转换,我们只需要拿来即用就行。当然,除了数组外,还有字典(Dictionary)、集合(Set)、字符串(String)也是一样。 问题 不过仔细一想,会发现,NSArray是类类型,而Array是结构体类型。一个是引用类型,一个是值类型,它们是怎样实现无缝转换的呢?这让我们想到了Cocoa Foundation与Core Foundation之间转换的toll-free bridging技术。那NSArray与Array之间是不是也应该有类似的桥接实现呢? Objective-C Bridge 我们将鼠标移动到Array上,然后"cmd+鼠标点击",进入到Swift的声明文件中,在Array的注释中,可以看到下面这段: /// Objective-C Bridge/// ==================/// The main distinction between Array and the other array types is that it interoperates seamlessly and efficiently with Objective-C./// Array is considered bridged to Objective-C iff Element is bridged to Objective-C.// ......可以看到Array与Objective-C的数组之间确实存在某种桥接技术,我们暂且称之为"Objective-C Bridge"桥接。那这又是如何实现的呢? 我们在当前文件中搜索bridge,会发现有这样一个协议:_ObjectiveCBridgeable。我们先来看看它的声明: /// A Swift Array or Dictionary of types conforming to `_ObjectiveCBridgeable` can be passed to Objective-C as an NSArray or NSDictionary, respectively. The elements of the resulting NSArray or NSDictionary will be the result of calling `_bridgeToObjectiveC` on each element of the source container.public protocol _ObjectiveCBridgeable {}即一个Swift数组或字典,如果其元素类型实现了_ObjectiveCBridgeable协议,则该数组或字典可以被转换成Objective-C的数组或字典。对于_ObjectiveCBridgeable协议,我们目前所能得到的文档就只有这些,也看不到它里面声明了什么属性方法。不过,可以看到这个协议是访问控制权限是public,也就意味着可以定义类来实现这个接口。这就好办了,下面就来尝试实现这样一个转换。 Objective-C类与Swift结构体的互转示例 在此先定义一个Objective-C类,如下所示: // Mobile.h@interface Mobile : NSObject@property (nonatomic, strong) NSString *brand;@property (nonatomic, strong) NSString *system;- (instancetype)initWithBrand:(NSString *)brand system:(NSString *)system;@end// Mobole.m@implementation Mobile- (instancetype)initWithBrand:(NSString *)brand system:(NSString *)system { self = [super init]; if (self) { _brand = brand; _system = system; } return self;}@end同样,我定义一个Swift结构体,如下所示: struct SwiftMobile { let brand: String let system: String}要想实现Mobile类与SwiftMobile结构体之间的互转,则SwiftMobile结构体需要实现_ObjectiveCBridgeable协议,如下所示: extension SwiftMobile: _ObjectiveCBridgeable { typealias _ObjectiveCType = Mobile // 判断是否能转换成Objective-C对象 static func _isBridgedToObjectiveC() -> Bool { return true } // 获取转换的目标类型 static func _getObjectiveCType() -> Any.Type { return _ObjectiveCType.self } // 转换成Objective-C对象 func _bridgeToObjectiveC() -> _ObjectiveCType { return Mobile(brand: brand, system: system) } // 强制将Objective-C对象转换成Swift结构体类型 static func _forceBridgeFromObjectiveC(source: _ObjectiveCType, inout result: SwiftMobile?) { result = SwiftMobile(brand: source.brand, system: source.system) } // 有条件地将Objective-C对象转换成Swift结构体类型 static func _conditionallyBridgeFromObjectiveC(source: _ObjectiveCType, inout result: SwiftMobile?) -> Bool { _forceBridgeFromObjectiveC(source, result: &result) return true }}
|