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
}