假设我想调用一个Cocoa方法(在Objective-C中)会给我一个NSArray,然后将它传递给一个采用NSArray的Cocoa方法。有了这样的代码:
let a: [AnyObject] = [] // Imagine calling a method that returns a huge NSArray. let mutable = NSMutableArray() mutable.addObjectsFromArray(a)
它看起来像巨大的NSArray将被分配到一个Swift数组,当被分配给一个然后桥接回NSArray作为一个参数传递。至少这是从分析和查看拆卸看起来如何。
当我不需要在Swift中使用数组时,是否有办法避免这些潜在的慢转换?当我刚从Cocoa接收它然后再传回Cocoa?
起初,我认为这有助于添加类型信息:
let a: NSArray = [] // Imagine calling a method that returns a huge NSArray. let mutable = NSMutableArray() mutable.addObjectsFromArray(a as [AnyObject])
但是后来我必须将参数转换为Swift数组,否则编译器会抱怨。
此外,代码的拆卸如下:
let c: NSArray = mutable.subarrayWithRange(NSMakeRange(0,50))
显示调用__TF10Foundation22_convertNSArrayToArrayurFGSqCSo7NSArray_GSaq__和__TFer10FoundationSa19_bridgeToObjectiveCurfGSaq__FT_CSo7NSArray,似乎将返回值转换为Swift,然后返回到Objective-C。 (即使发布版本也会发生。)我曾经希望通过键入c作为NSArray,不需要桥接。
我担心这可能导致inefficiencies具有非常大的数据结构,许多不同的常规转换,以及懒惰/代理的集合,因为它们不一定很大,但计算成本可能很高。如果从Swift不能访问,那么可以从Objective-C代码中获得receive这样一个数组,并将其传递回来,而无需实现数组的所有元素。
这是一个非常different performance模型,而不是核心基金会/基金会,桥接是免费的。有很多情况下,代码会传递对象,假设它将是O(1),如果这些对象不可见地改变为O(n),则外部算法可能会变成二次或更差。在这种情况下,我不清楚应该做什么。如果没有办法关闭桥接,似乎所有触及这些对象的东西都需要在Objective-C中重写。
以下是基于上述示例的一些示例时序代码:
NSArray *getArray() { static NSMutableArray *result; if (!result) { NSMutableArray *array = [NSMutableArray array]; for (NSUInteger i = 0; i < 1000000; i++) { [array addObjectsFromArray:@[@1,@2,@3,@"foo",@"bar",@"baz"]]; } result = array; } return result; } @interface ObjCTests : XCTestCase @end @implementation ObjCTests - (void)testObjC { // 0.27 seconds [self measureBlock:^{ NSArray *a = getArray(); NSMutableArray *m = [NSMutableArray array]; [m addObjectsFromArray:a]; }]; } @end class SwiftTests: XCTestCase { func testSwift() { // 0.33 seconds self.measureBlock() { let a: NSArray = getArray() as NSArray let m = NSMutableArray() m.addObjectsFromArray(a as [AnyObject]) } } func testSwiftPure() { // 0.83 seconds self.measureBlock() { let a = getArray() var m = [AnyObject]() m.appendContentsOf(a) } } }
在这个例子中,testSwift()比testObjC()慢约22%。只是为了好玩,我尝试用本地Swift数组进行数组追加,而这慢得多。
一个相关的问题是,当Objective-C代码通过Swift代码一个NSMutableString时,Swift String结束了一个可变字符串的副本。这在Swift的背后不会意外突变的意义上是好的。但是,如果你需要做的只是将一个字符串传递给Swift并简要地看一下,这个副本可能会增加意外的开销。
extension NSMutableArray { func addObjectsFromNSArray(array:NSArray) { for item in array { self.addObject(item); } } }
现在我有时间真的玩这个,而不是在理论上说话,我要修改我的答案
创建扩展名,而是在目标c文件中执行
@interface NSMutableArray(Extension) - (void)addObjectsFromNSArray:(NSObject*) array; @end @implementation NSMutableArray(Extension) - (void)addObjectsFromNSArray:(NSObject*) array { [self addObjectsFromArray:(NSArray*)array]; } @end
我发现代码的工作速度要快很多,这样做。 (从我的测试几乎两倍)
testSwift 4.06秒
testSwiftPure 7.97秒
testSwiftExtension 2.30秒