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

我正在使用Objective-C编写一个API,并希望它能在
Swift中很好地运行.我在使用“for..in”语法时遇到了麻烦.我想我需要实现Sequence协议,但我找不到任何从Objective-C这样做的例子.只是引用Sequence给出了错误:没有名为’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

最佳答案 基金会的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类,你很好.

点赞