NSFastEnumeration在Swift中

我试图将Objective-C项目转换为swift,但我无法find如何使用NSFastEnumeration符合NSFastEnumeration类的对象。

这里是ObjC中的代码:

// get the decode results id<NSFastEnumeration> results = [info objectForKey: ZBarReaderControllerResults]; ZBarSymbol *symbol = nil; for(symbol in results) // just grab the first barcode break; 

到目前为止,我试图find如何做到这一点,但这似乎并不工作,这里是快速代码:

 var results: ZBarSymbolSet = infoDictionary?.objectForKey(ZBarReaderControllerResults) as ZBarSymbolSet var symbol : ZBarSymbol? = nil; for symbol in results { //just grab first barcode break; } 

错误进入条件 – “ZBarSymbolSet”没有一个名为“Generator”的成员

我究竟做错了什么?

这是屏幕截图 在这里输入图像说明

在swift框架文件周围戳了一下后,我终于find了这个很好的类NSFastGeneratorNSSet和朋友似乎使用相同的Generator

对于ZBarSymbolSet ,下面介绍如何扩展它以支持for-in循环:

 extension ZBarSymbolSet: SequenceType { public func generate() -> NSFastGenerator { return NSFastGenerator(self) } } 

更新:看起来像Swift 2.0的协议扩展为我们解决了这个问题!

您定义的类ZBarSymbolSet需要实现Swift SequenceType接口,以便for <identifier> in <sequence>语法中for <identifier> in <sequence>SequenceType接口是

 protocol SequenceType : _Sequence_Type { typealias Generator : GeneratorType func generate() -> Generator } 

因此您可以在错误消息中看到提及的Generator

另外在语法中:

 for <identifier> in <sequence> { <statements> } 

<identifer>仅在<statements>范围内。 因此,你在if中的第二次使用symbol将超出范围和错误。 一个适当的习惯用法是:

 var symbolFound : ZBarSymbol? for symbol in result { symbolFound = symbol break } if symbolFound ... 

如果当然,但是当ZBarSymbolSet实现SequenceType它也会实现带有subscript CollectionType ,因此整个'find第一个元素'的代码将会是var symbol = result[0]

 Step1: extension ZBarSymbolSet: SequenceType { public func generate() -> NSFastGenerator { return NSFastGenerator(self) } } Step2: var results: NSFastEnumeration = info.objectForKey(ZBarReaderControllerResults) as NSFastEnumeration var symbolFound : ZBarSymbol? for symbol in results as ZBarSymbolSet { symbolFound = symbol as? ZBarSymbol break } resultString = NSString(string: symbolFound!.data) 

这里是约翰·埃斯特罗普的斯威夫特3的答案:

 extension ZBarSymbolSet: Sequence { public typealias Iterator = NSFastEnumerationIterator public func makeIterator() -> NSFastEnumerationIterator { return NSFastEnumerationIterator(self) } } 

那么你的for-in循环看起来像这样:

 for element in results { let symbol = element as! ZBarSymbol // ... } 

这个答案也可以通过采用IteratorProtocol来改进,所以你可以指定元素关联types为ZBarSymbol 。 我还没有想出如何做到这一点呢。

另外,如果您知道ZBarSymbolSet中的所有对象都是ZBarSymbol对象(因为ObjC不强制所有对象都是ZBarSymbol对象),您可以执行以下操作:

 extension ZBarSymbolSet { public struct ZBarSymbolSetIterator { public typealias Element = ZBarSymbol private let enumerator: NSFastEnumerationIterator init(_ symbols: ZBarSymbolSet) { self.enumerator = NSFastEnumerationIterator(symbols) } public mutating func next() -> ZBarSymbol { if let object = self.enumerator.next() { return object as? ZBarSymbol } else { return nil } } } public func makeIterator() -> ZBarSymbolSetIterator { return ZBarSymbolSetIterator(self) } } 

现在你的for循环将如下所示:

 for element in results { // element is a ZBarSymbol }