【问题标题】:NSFastEnumeration in SwiftSwift 中的 NSFastEnumeration
【发布时间】:2014-11-05 10:51:27
【问题描述】:

我正在尝试将 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;

到目前为止,我试图找到如何做到这一点,但这似乎不起作用,这里是 swift 代码:

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

    var symbol : ZBarSymbol? = nil;

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

错误来自条件 - “ZBarSymbolSet”没有名为“Generator”的成员

我做错了什么?

这是屏幕截图

【问题讨论】:

  • 我也想听听一个真正的解决方案(目前唯一的答案只是说明它为什么不起作用。)NSFastEnumeration 是一个在NSFoundation 中广泛使用的协议(NSSetNSHashTableNSMapTableNSPointerArray 等)并且扩展所有这些类只是为了符合 SequenceType 感觉是多余的,而这些类已经支持相同的 for-in 构造在 Objective-C 中。

标签: ios objective-c swift


【解决方案1】:

这是一种无需编写扩展的方法

    var iterator = NSFastEnumerationIterator(collection)
    while let element = iterator.next() {
        // use element
    }

【讨论】:

    【解决方案2】:

    另外,如果您知道 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
    }
    

    【讨论】:

      【解决方案3】:

      这是 John Estropia 对 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。我还没想好怎么做。

      【讨论】:

        【解决方案4】:

        在 swift 框架文件中翻了一阵子后,我终于找到了一个名为 NSFastGenerator 的好类。 NSSet 和朋友好像用的是同一个Generator

        对于ZBarSymbolSet,以下是扩展它以支持for-in 循环的方法:

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

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

        【讨论】:

        • 这太棒了,但 Apple 应该默认为所有符合 NSFastEnumeration 的类执行此操作。事实上,我不得不为我想说for...in 的每个 NSFastEnumeration 类重复这个扩展,这太疯狂了。
        • 虽然 Swift 2.0 支持协议扩展,但它们不能有继承子句,因此该技术似乎仍然仅限于类。
        • @lukhnos NSFastEnumeration 协议适用于旧的objective-c 集合。您不应该将它用于结构;只需使用 SequenceType。
        【解决方案5】:
        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)
        

        【讨论】:

        • 感谢 Alok,但约翰的回答解决了我面临的问题。我认为您的回答将帮助其他人了解全貌。
        • 在 Swift 2 中,我收到错误 Could not cast value of type '__NSArrayM' to 'ZBarSymbolSet' 在这一行 for symbol in results as ZBarSymbolSet.
        【解决方案6】:

        您定义的类 ZBarSymbolSet 需要实现 Swift SequenceType 接口才能在 for &lt;identifier&gt; in &lt;sequence&gt; 语法中使用。 SequenceType 接口是

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

        因此您会在错误消息中看到提到了Generator

        同样在语法中:

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

        &lt;identifer&gt; 仅在 &lt;statements&gt; 的范围内。因此,您在if 中第二次使用symbol 将超出范围并出现错误。一个恰当的成语是:

        var symbolFound : ZBarSymbol?
        
        for symbol in result {
          symbolFound = symbol
          break
        }
        
        if symbolFound ...
        

        如果当然,但时间 ZBarSymbolSet 实现 SequenceType 它也将实现 CollectionTypesubscript,因此整个“查找第一个元素”代码将是 var symbol = result[0]

        【讨论】:

        • 我无法编辑 ZBarSymbolSet,因为我正在使用 ZBar SDK zbar.sourceforge.net,一个静态库。任何替代???
        • 子类化或扩展它
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-01-16
        • 1970-01-01
        • 1970-01-01
        • 2011-06-19
        • 1970-01-01
        • 2012-08-28
        相关资源
        最近更新 更多