2014-09-11 29 views
14

我想将一个Objective-C项目转换为swift,但我无法找到如何将NSFastEnumeration用于符合NSFastEnumeration的类的对象。Swift中的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; 

到目前为止,我试图找到如何做到这一点,但是这母鹿不似乎工作,这里是SWIFT代码:

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

    var symbol : ZBarSymbol? = nil; 

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

的错误进入条件 - “ZBarSymbolSet”没有名为“发生器”的成员

我在做什么错?

下面是屏幕截图 enter image description here

+0

我想听听这个,以及一个真正的解决办法'NSFastEnumeration'是一个频繁使用的协议各地(唯一的答案,因为现在只是指出为什么它不工作。) 'NSFoundation'('NSSet','NSHa shTable','NSMapTable','NSPointerArray'等),当Objective-C中的那些类已经支持相同的'for-in'构造时,为了符合'SequenceType',扩展所有这些类是多余的。 – 2014-09-16 15:08:10

回答

22

过了一会在swift框架文件中,我终于找到了这个叫NSFastGenerator的好课堂。 NSSet和朋友似乎使用相同的Generator

对于ZBarSymbolSet,这里是你如何想扩展它支持for-in循环:

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

更新:看起来像雨燕2.0的协议扩展解决了这个问题我们!

+1

这太棒了,但苹果应该默认为所有他们自己的NSFastEnumeration-conforming类。事实上,我不得不为每个NSFastEnumeration类重复这个扩展,我想说'for ... in',这是疯了。 – matt 2014-10-26 20:13:26

+0

虽然Swift 2.0支持协议扩展,但它们不能有继承子句,因此该技术似乎仍然仅限于类。 – lukhnos 2015-09-22 22:39:32

+0

@lukhnos NSFastEnumeration协议适用于旧的Objective-C集合。你不应该将它用于结构;只需使用SequenceType。 – 2015-09-23 00:13:16

3

你定义的类ZBarSymbolSet需要实现以是可用在for <identifier> in <sequence>语法雨燕SequenceType接口。该SequenceType接口

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

,因此你看到的Generator提到在您的错误信息报告。

另外在语法:

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

<identifer>仅在范围为<statements>。因此,您在if中第二次使用symbol将超出范围并出现错误。一个正确的成语是:

var symbolFound : ZBarSymbol? 

for symbol in result { 
    symbolFound = symbol 
    break 
} 

if symbolFound ... 

如果过程,但时间ZBarSymbolSet实现SequenceType它也将实现CollectionTypesubscript从而对整个“找到的第一个元素”代码将是var symbol = result[0]

+0

我无法编辑ZBarSymbolSet,因为我使用ZBar SDK http://zbar.sourceforge.net,一个静态库。任何替代? – 2014-09-11 15:32:22

+1

子类或扩展它 – 2014-09-11 15:50:59

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

谢谢阿洛克,但约翰的回答解决了我面临的问题。我认为你的回答会帮助其他人弄清楚全貌。 – 2014-09-19 12:14:15

+0

在Swift 2中,我收到了错误**无法将类型'__NSArrayM'的值转换为'ZBarSymbolSet'**在此行'作为ZBarSymbolSet结果中的符号。 – Isuru 2016-03-16 06:52:58

2

这里是约翰Estropia对斯威夫特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。我还没有想出如何做到这一点呢。

1

另外,如果你知道,在所有对象的ZBarSymbolSetZBarSymbol对象(因为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 
}