NSFastEnumeration в 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;
}
ошибка возникает для условия - "ZBarSymbolSet" не имеет члена с именем "Generator"
Что я делаю неправильно?
Вот скриншот
![enter image description here]()
Ответы
Ответ 1
Спустя некоторое время, прокручивая быстрые файлы фреймворков, я наконец нашел этот класс, который называется NSFastGenerator
. NSSet
и друзья, похоже, используют один и тот же Generator
.
Для ZBarSymbolSet
, как вы можете расширить его для поддержки циклов for-in
:
extension ZBarSymbolSet: SequenceType {
public func generate() -> NSFastGenerator {
return NSFastGenerator(self)
}
}
Обновление: Похоже, что расширители протокола Swift 2.0 исправили это для нас!
Ответ 2
Ваш определенный класс 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]
Ответ 3
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
Вот ответ Джон Эстропией для 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
. Я еще не понял, как это сделать.
Ответ 5
Кроме того, если вы знаете, что все объекты в 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
}