A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

我们知道在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    }}

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马