2014-09-11 7 views
14

Sto cercando di convertire un progetto Objective-C in swift, ma non riesco a trovare come utilizzare NSFastEnumeration per un oggetto di una classe conforme a NSFastEnumeration.NSFastEnumeration in Swift

Ecco il codice in objC:

// get the decode results 
id<NSFastEnumeration> results = [info objectForKey: ZBarReaderControllerResults]; 

ZBarSymbol *symbol = nil; 
for(symbol in results) 
    // just grab the first barcode 
    break; 

finora ho cercato di trovare il modo di fare questo, ma questo doe non sembra il lavoro, ecco il codice swift:

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

    var symbol : ZBarSymbol? = nil; 

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

la errore entra in condizione - "ZBarSymbolSet" non ha un membro chiamato "Generator"

Cosa sto facendo male?

Ecco la schermata enter image description here

+0

mi piacerebbe sentire una vera e propria soluzione per questo pure 'NSFastEnumeration' è un protocollo pesantemente utilizzato in tutto (l'unica risposta fin d'ora appena stati il ​​motivo per cui non funziona.) 'NSFoundation' (' NSSet', 'NSHa shTable', 'NSMapTable',' NSPointerArray', ecc.) e ritiene ridondante estendere tutte queste classi solo per conformarsi a 'SequenceType', quando lo stesso costrutto' for-in' era già supportato per quelle classi in Objective-C . –

risposta

22

Dopo un po ' frugando tra i file di framework rapidi, ho finalmente trovato questa bella classe chiamata NSFastGenerator. NSSet e gli amici sembrano utilizzare lo stesso Generator.

Per ZBarSymbolSet, ecco come ci si estendo a sostenere for-in loop:

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

Aggiornamento: Sembra estensioni di protocollo Swift 2.0 del risolto questo per noi!

+1

È brillante, ma Apple dovrebbe eseguire questa operazione per impostazione predefinita per tutte le loro classi conformi a NSFastEnumeration. Così com'è, devo ripetere questa estensione per ogni classe NSFastEnumeration in cui voglio dire "for ... in", che è pazzesco. – matt

+0

Sebbene Swift 2.0 supporti le estensioni del protocollo, non possono avere una clausola di ereditarietà, e quindi la tecnica sembra ancora limitata alle classi. – lukhnos

+0

@lukhnos il protocollo NSFastEnumeration è pensato per vecchie raccolte di obiettivi-c. Non dovresti usarlo per le strutture; basta usare SequenceType. –

3

La classe definita ZBarSymbolSet ha la necessità di implementare l'interfaccia Swift SequenceType al fine di essere utilizzabile in for <identifier> in <sequence> sintassi. L'interfaccia è SequenceType

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

e quindi si vede la menzione di Generator come riportato nel messaggio di errore.

anche la sintassi:

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

l'<identifer> è solo nell'ambito per <statements>. Pertanto il tuo secondo utilizzo di symbol nello if sarà fuori portata e un errore. Un linguaggio corretto sarebbe:

var symbolFound : ZBarSymbol? 

for symbol in result { 
    symbolFound = symbol 
    break 
} 

if symbolFound ... 

Se naturalmente, ma il tempo ZBarSymbolSet implementa SequenceType sarebbe anche implementare CollectionType con subscript e così l'intero 'trovare il primo elemento' codice sarebbe var symbol = result[0]

+0

Non riesco a modificare ZBarSymbolSet poiché sto usando ZBar SDK http://zbar.sourceforge.net, una libreria statica. Qualche alternativa ??? –

+1

sottoclassi o estendi –

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) 
+0

Grazie Alok, ma la risposta di John ha risolto il problema che stavo affrontando. Penso che la tua risposta aiuterà gli altri a capire il quadro completo. –

+0

In Swift 2, viene visualizzato l'errore ** Impossibile trasmettere il valore di tipo '__NSArrayM' a 'ZBarSymbolSet' ** in questa riga 'per il simbolo nei risultati come ZBarSymbolSet'. – Isuru

2

Ecco la risposta di John Estropia per Swift 3:

extension ZBarSymbolSet: Sequence { 

    public typealias Iterator = NSFastEnumerationIterator 

    public func makeIterator() -> NSFastEnumerationIterator { 
     return NSFastEnumerationIterator(self) 
    } 

} 

Poi si per-in loop sarebbe simile a questa:

for element in results { 
    let symbol = element as! ZBarSymbol 
    // ... 
} 

Questa risposta potrebbe essere migliorata con l'adozione anche la IteratorProtocol in modo da poter specificare il tipo di elemento associato come ZBarSymbol. Non ho ancora capito come farlo.

1

Inoltre, se si sa che tutti gli oggetti nel vostro ZBarSymbolSet sono ZBarSymbol oggetti (in quanto objC non applica tutti gli oggetti che sono ZBarSymbol oggetti), è possibile effettuare le seguenti operazioni:

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) 
    } 
} 

Ora il vostro ciclo for sarà simile a questa:

for element in results { 
    // element is a ZBarSymbol 
}