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了这个很好的类NSFastGenerator
。 NSSet
和朋友似乎使用相同的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 }