Swift中的NSFastEnumeration

时间:2014-09-11 13:06:23

标签: ios objective-c swift

我正在尝试将Objective-C项目转换为swift,但我无法找到如何将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;

到目前为止,我试图找到如何做到这一点,但这似乎不起作用,这里是快速的代码:

var results: ZBarSymbolSet = infoDictionary?.objectForKey(ZBarReaderControllerResults) as ZBarSymbolSet

    var symbol : ZBarSymbol? = nil;

    for symbol in results
    {    //just grab first barcode
        break;
    }

错误来自条件 - &#34; ZBarSymbolSet&#34;没有名为&#34; Generator&#34;

的成员

我做错了什么?

这是屏幕截图 enter image description here

6 个答案:

答案 0 :(得分:22)

在快速浏览swift框架文件一段时间后,我终于找到了一个名为NSFastGenerator的好类。 NSSet和朋友似乎使用相同的Generator

对于ZBarSymbolSet,以下是将其扩展为支持for-in循环的方式:

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

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

答案 1 :(得分:3)

您定义的类ZBarSymbolSet需要实现Swift SequenceType接口才能在for <identifier> in <sequence>语法中使用。 SequenceType接口是

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

因此您会在错误消息中看到提及Generator的内容。

同样在语法中:

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

<identifer>仅适用于<statements>。因此,symbolif的第二次使用将超出范围且出错。一个恰当的习语是:

var symbolFound : ZBarSymbol?

for symbol in result {
  symbolFound = symbol
  break
}

if symbolFound ...

如果是课程,但时间ZBarSymbolSet实施SequenceType,那么它也会CollectionTypesubscript实施,因此整个&#39;找到第一个元素&#39}。代码为var symbol = result[0]

答案 2 :(得分:3)

这是John Estropia对Swift 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可以改进此答案,因此您可以将元素关联类型指定为ZBarSymbol。我还没弄明白怎么做。

答案 3 :(得分:2)

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)

答案 4 :(得分:1)

另外,如果您知道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
}

答案 5 :(得分:0)

这是一种无需编写扩展名的方法

    var iterator = NSFastEnumerationIterator(collection)
    while let element = iterator.next() {
        // use element
    }