Mic*_*sai 18 macos cocoa swift
使用Swift时,Cocoa框架被声明为返回本机Swift类型,即使框架实际上返回了Objective-C对象.同样,这些方法将Swift类型作为参数,这是有意义的.
假设我想调用一个Cocoa方法(在Objective-C中)会给我一个NSArray,然后将它传递给一个需要的Cocoa方法NSArray.使用这样的代码:
let a: [AnyObject] = [] // Imagine calling a method that returns a huge NSArray.
let mutable = NSMutableArray()
mutable.addObjectsFromArray(a)
Run Code Online (Sandbox Code Playgroud)
看起来巨大NSArray的东西将被分配到Swift数组a,然后NSArray在作为参数传递时桥接回一个Swift数组.至少这是从剖析和看反汇编看起来的样子.
当我不需要在Swift中实际使用数组时,有没有办法避免这些可能很慢的转换?当我刚从Cocoa接收它然后将它传回Cocoa时?
起初,我认为有助于添加类型信息a:
let a: NSArray = [] // Imagine calling a method that returns a huge NSArray.
let mutable = NSMutableArray()
mutable.addObjectsFromArray(a as [AnyObject])
Run Code Online (Sandbox Code Playgroud)
但是后来我必须将参数转换为Swift数组,否则编译器会抱怨.
此外,代码的反汇编如:
let c: NSArray = mutable.subarrayWithRange(NSMakeRange(0, 50))
Run Code Online (Sandbox Code Playgroud)
显示调用__TF10Foundation22_convertNSArrayToArrayurFGSqCSo7NSArray_GSaq__和__TFer10FoundationSa19_bridgeToObjectiveCurfGSaq__FT_CSo7NSArray,似乎将返回值转换为Swift,然后返回到Objective-C.(即使使用Release版本也会发生这种情况.)我希望通过键入来完成,c因为NSArray不需要桥接.
我担心这会导致非常大的数据结构效率低下,许多不同的常规转换,以及懒惰/代理的集合,因为它们不一定很大但计算起来可能很昂贵.能够从Objective-C代码接收这样的数组并将其传递回去而不必实现数组的所有元素(如果它们永远不会从Swift访问)那将是很好的.
这是一个非常不同的 性能模型,而不是核心基金会/基金会,其中桥接是免费的.有很多情况下,代码来回传递对象,假设它是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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中,testSwift()比约慢22%testObjC().只是为了好玩,我尝试使用本机Swift数组进行数组追加,这速度要慢得多.
一个相关的问题是,当Objective-C代码传递Swift代码时NSMutableString,Swift String最终会得到一个可变字符串的副本.这是好的,因为它不会在Swift的背后突然变异.但是,如果你需要做的只是将一个字符串传递给Swift并简要地查看它,这个副本可能会增加意想不到的开销.
你尝试过延期吗?
extension NSMutableArray
{
func addObjectsFromNSArray(array:NSArray)
{
for item in array
{
self.addObject(item);
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在我有时间实际玩这个而不是理论上谈论,我将修改我的答案
创建一个扩展,但在目标 c 文件中执行它
@interface NSMutableArray(Extension)
- (void)addObjectsFromNSArray:(NSObject*) array;
@end
@implementation NSMutableArray(Extension)
- (void)addObjectsFromNSArray:(NSObject*) array
{
[self addObjectsFromArray:(NSArray*)array];
}
@end
Run Code Online (Sandbox Code Playgroud)
我发现这样做代码的运行速度要快得多。(根据我的测试,几乎是 2 倍)
测试Swift 4.06 秒
testSwiftPure 7.97 秒
testSwiftExtension 2.30 秒
| 归档时间: |
|
| 查看次数: |
858 次 |
| 最近记录: |