2014-09-11 10 views
14

Próbuję przekonwertować projekt Objective-C na szybki, ale nie jestem w stanie znaleźć sposobu użycia NSFastEnumeration dla obiektu klasy, który jest zgodny z NSFastEnumeration.NSFastEnumeration w Swift

Oto kod w ObjC:

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

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

tej pory starałem się dowiedzieć, jak to zrobić, ale to łania nie wydaje pracy, tutaj jest kod SWIFT:

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

    var symbol : ZBarSymbol? = nil; 

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

Wystąpił błąd warunku - "ZBarSymbolSet" nie ma członka o nazwie "Generator"

Co robię źle?

Oto zrzut ekranu enter image description here

+0

Chciałbym usłyszeć prawdziwe rozwiązanie tego oraz 'NSFastEnumeration' jest to mocno używany protokół całego (jedyna odpowiedź jak na razie po prostu stwierdza, dlaczego to nie działa). 'NSFoundation' (' NSSet', 'NSHa shTable', 'NSMapTable',' NSPointerArray', etc) i czuje się zbędnym rozszerzenie wszystkich tych klas tylko po to, aby dostosować się do 'SequenceType', kiedy ten sam konstrukt' for-in' był już obsługiwany dla tych klas w Objective-C . –

Odpowiedz

22

Po pewnym czasie przeglądając szybkie pliki frameworku, w końcu znalazłem tę fajną klasę o nazwie NSFastGenerator. NSSet i znajomi wydają się używać tego samego Generator.

Dla ZBarSymbolSet, oto jak chcesz przedłużyć go wspierać for-in pętle:

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

Aktualizacja: Wygląda rozszerzenia protokołu Swift 2.0 na stałe to dla nas!

+1

To jest genialne, ale Apple powinno to zrobić domyślnie dla wszystkich klas zgodnych z NSFastEnumeration. Tak jak to jest, muszę powtórzyć to rozszerzenie dla każdej klasy NSFastEnumeration, gdzie chcę powiedzieć 'for ... in', czyli nuts. – matt

+0

Chociaż Swift 2.0 obsługuje rozszerzenia protokołów, nie może mieć klauzuli dziedziczenia, więc technika nadal wydaje się być ograniczona do klas. – lukhnos

+0

@lukhnos protokół NSFastEnumeration jest przeznaczony dla starych kolekcji obiektów-c. Nie powinieneś używać go dla struktur; po prostu użyj SequenceType. –

3

Twój zdefiniowana klasa ZBarSymbolSet musi wdrożyć SequenceType interfejs Swift aby być użyteczny w for <identifier> in <sequence> składni. Interfejs SequenceType jest

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

a więc widać wzmianki Generator jak podano w komunikacie o błędzie.

Również w składni:

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

<identifer> jest tylko w zakresie do <statements>. Zatem drugie użycie symbol w if będzie poza zakresem i błędem. Jeden właściwy idiom byłoby:

var symbolFound : ZBarSymbol? 

for symbol in result { 
    symbolFound = symbol 
    break 
} 

if symbolFound ... 

Jeśli oczywiście, ale czas ZBarSymbolSet realizuje SequenceType byłoby również wdrożyć CollectionType z subscript a więc cała „znaleźć pierwszy element” Kod byłoby var symbol = result[0]

+0

Nie mogę edytować ZBarSymbolSet, ponieważ używam biblioteki ZBar SDK http://zbar.sourceforge.net, biblioteki statycznej. Jakieś zastępcze? –

+1

podklasuj lub rozszerz go –

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

Dzięki Alok, ale odpowiedź Johna rozwiązała problem, z którym miałem do czynienia. Myślę, że twoja odpowiedź pomoże innym zrozumieć pełny obraz. –

+0

W Swift 2, otrzymuję błąd ** Nie można rzucić wartość typu "__NSArrayM" na "ZBarSymbolSet" ** w tym wierszu 'dla symbolu w wynikach jako ZBarSymbolSet'. – Isuru

2

Oto odpowiedź Johna Estropia dla Swift 3:

extension ZBarSymbolSet: Sequence { 

    public typealias Iterator = NSFastEnumerationIterator 

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

} 

Następnie do w pętli będzie wyglądać następująco:

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

Ta odpowiedź może być poprawiona przez również przyjmując IteratorProtocol, aby można było określić typ skojarzonego elementu jako ZBarSymbol. Nie wiem jeszcze, jak to zrobić.

1

Również, jeśli wiesz, że wszystkie obiekty w twojej ZBarSymbolSetZBarSymbol obiekty (od ObjC nie wymusza wszystkie obiekty będące ZBarSymbol obiektów), można wykonać następujące czynności:

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

teraz Twój pętli for będzie wyglądać następująco:

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