如何从Objective-C实现Sequence(允许Swift的for-in语法)?

时间:2016-09-28 20:59:54

标签: objective-c swift

我正在使用Objective-C编写一个API,并希望它能在Swift中很好地运行。我在使用“for..in”语法时遇到了麻烦。我想我需要实现Sequence协议,但我找不到任何从Objective-C做这个的例子。只需引用Sequence即可error: no type or protocol named 'Sequence'。是否有特殊的#import可以访问它或什么?

我尝试实现NSFastEnumeration协议,想想它可能会在Swift中神奇地转换为Sequence,但这不起作用。

///// Obj-C Code
@interface Foo : NSObject<NSFastEnumeration>
...
@end

///// Swift Code
var foo: Foo = Foo()

// ERROR: Type 'Foo' does not conform to protocol 'Sequence'
for y in foo {
    print("Got a y.")
}

编辑:看起来从NSEnumerator继承让我更接近,但也不是很有效:

///// Obj-C Code
@interface Foo : NSEnumerator<NSString *>
...
@end

///// Swift Code
// ERROR: 'NSFastEnumerationIterator.Element' (aka 'Any') is not convertible to 'String'
for y: String in foo {
    print("Got \(y)")
}

编辑2:我仍然没有一个好的解决方案并记录了一个错误:https://bugs.swift.org/browse/SR-2801

1 个答案:

答案 0 :(得分:2)

基础的Swift扩展包括一些支持,使得采用NSFastEnumeration的类也支持Swift Sequence协议......但不是自动的。

一种方法是在Swift中扩展你的ObjC类型并传递给NSFastEnumerationIterator类型:

extension Foo: Sequence {
    public func makeIterator() -> NSFastEnumerationIterator {
        return NSFastEnumerationIterator(self)
    }
}

NSFastEnumerationIterator(以及所有形式的ObjC枚举)都是类型擦除,因此它们不会提供有关您正在迭代的元素类型的任何信息。这意味着您可以执行此操作(添加上述扩展名后):

var foo: Foo = Foo()
for y in foo {
    print("Got a y.")
}

...但y的静态类型始终为Any。如果您想要对foo成员进行输入访问,则需要使用强制转换或过滤循环:

for y in foo where y is String {
    print("Got \(y)")
}

可悲的是,如果你的班级采用ObjC泛型,似乎没有办法让这项工作 - 你会得到一个错误“扩展一般的Objective-C类无法访问即使在SE-0057中采用运行时类型内省方法,运行时“类”的通用参数“也是如此。但是对于非泛型的ObjC课程,你很好。