NSFastEnumeration в Swift

Я пытаюсь преобразовать проект Objective-C в быстрый, но я не могу найти, как использовать 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;
    }

ошибка приходит для условия - "ZBarSymbolSet" не имеет члена с именем "Генератор"

Что я делаю неправильно?

Вот снимок экрана

6 ответов

Решение

Через некоторое время изучая файлы фреймворка, я наконец-то нашел этот классный класс NSFastGenerator, NSSet и друзья, кажется, используют то же самое Generator,

За ZBarSymbolSetвот как бы вы продлили это для поддержки for-in петли:

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

Обновление: похоже, расширения протокола Swift 2.0 исправили это для нас!

Вот ответ Джона Эстропии для 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, Я еще не понял, как это сделать.

Ваш определенный класс 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>, Таким образом, ваше второе использование symbol в if будет вне области видимости и ошибка. Одна правильная идиома будет:

var symbolFound : ZBarSymbol?

for symbol in result {
  symbolFound = symbol
  break
}

if symbolFound ...

Если конечно, но время ZBarSymbolSet инвентарь SequenceType было бы также реализовать CollectionType с subscript и, таким образом, весь код "найти первый элемент" будет var symbol = result[0]

Вот способ сделать это без написания расширения

    var iterator = NSFastEnumerationIterator(collection)
    while let element = iterator.next() {
        // use element
    }
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)

Кроме того, если вы знаете, что все объекты в вашем 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
}
Другие вопросы по тегам