Tengo una simple enumeración que me gustaría repetir. Para este propósito, he adoptado la Secuencia y IteratorProtocol como se muestra en el siguiente código. Por CIERTO, esta puede ser la copia/pega a un Patio de recreo en Xcode 8.

import UIKit

enum Sections: Int {
  case Section0 = 0
  case Section1
  case Section2
}

extension Sections : Sequence {
  func makeIterator() -> SectionsGenerator {
    return SectionsGenerator()
  }

  struct SectionsGenerator: IteratorProtocol {
    var currentSection = 0

    mutating func next() -> Sections? {
      guard let item = Sections(rawValue:currentSection) else {
        return nil
      }
      currentSection += 1
      return item
    }
  }
}

for section in Sections {
  print(section)
}

Pero el para-en el bucle genera el mensaje de error «Tipo» Secciones.Tipo’ no se ajusta al protocolo ‘Secuencia'».
El protocolo de conformidad es en mi extensión; así, lo que está mal con este código?

Sé que hay otras maneras de hacer esto, pero me gustaría entender lo que está mal con este enfoque.

Gracias.

Hay un número de respuestas que resolver su problema aquí (la pregunta es acerca del tipo de Cadena, pero la mayoría de las respuestas será trabajar con cualquier tipo): stackoverflow.com/questions/24007461/…
Yo tengo una respuesta puede consultar aquí stackoverflow.com/a/48960126/5372480

OriginalEl autor Phantom59 | 2016-12-27

6 Comentarios

  1. 10

    Nota que Martin solución puede ser refactorizado como un protocolo:

    import Foundation
    
    protocol EnumSequence
    {
        associatedtype T: RawRepresentable where T.RawValue == Int
        static func all() -> AnySequence<T>
    }
    extension EnumSequence
    {
        static func all() -> AnySequence<T> {
            return AnySequence { return EnumGenerator() }
        }
    }
    
    private struct EnumGenerator<T: RawRepresentable>: IteratorProtocol where T.RawValue == Int {
        var index = 0
        mutating func next() -> T? {
            guard let item = T(rawValue: index) else {
                return nil
            }
            index += 1
            return item
        }
    }

    Entonces, dada una enumeración

    enum Fruits: Int {
        case apple, orange, pear
    }

    que la palmada en el protocolo y un typealias:

    enum Fruits: Int, EnumSequence {
        typealias T = Fruits
        case apple, orange, pear
    }
    
    Fruits.all().forEach({ print($0) }) // apple orange pear

    OriginalEl autor Jano

  2. 8

    Actualización: Como de Swift 4.2, usted puede simplemente añadir el protocolo de conformidad
    a CaseIterable, ver Cómo enumerar una enumeración con el tipo de Cadena?.


    Se puede iterar sobre una valor de un tipo que se ajusta a la Sequence
    protocolo. Por lo tanto

    for section in Sections.Section0 {
      print(section)
    }

    sería compilar y dar el resultado esperado. Pero por supuesto que no es
    realmente lo que quieres, porque la elección del valor es arbitrario y el
    valor en sí misma no es necesaria en la secuencia.

    Que yo sepa, no hay ninguna manera para iterar sobre un tipo en sí, por lo que

    for section in Sections {
      print(section)
    }

    compila. Que requeriría que el «metatype» Sections.Type cumple
    a Sequence. Tal vez alguien demuestra que estoy equivocado.

    Lo que usted puede hacer es definir un tipo de método que devuelve una secuencia:

    extension Sections {
        static func all() -> AnySequence<Sections> {
            return AnySequence {
                return SectionsGenerator()
            }
        }
    
        struct SectionsGenerator: IteratorProtocol {
            var currentSection = 0
    
            mutating func next() -> Sections? {
                guard let item = Sections(rawValue:currentSection) else {
                    return nil
                }
                currentSection += 1
                return item
            }
        }
    
    }
    
    for section in Sections.all() {
        print(section)
    }
    Hay una Propuesta SE para, esencialmente, la «metatype» que sugieren; ver gist.github.com/andyyhope/2fc5b6bee8ee1346f688 Espero que adoptó como parece ser en general característica útil que evite todo tipo de soluciones personalizadas. Por ahora, me quedo con el de iterar sobre el tipo. Gracias!
    Otra referencia en su estado se puede encontrar aquí: github.com/apple/swift-evolution/pull/114
    Por favor, compruebe también este respuesta.. el que se muestra cómo crear un iterateEnum() función para muchas versiones de Swift.

    OriginalEl autor Martin R

  3. 3

    Este se ve mucho más simple:

    public protocol EnumSequence {
        init?(rawValue: Int)
    }
    
    public extension EnumSequence {
    
        public static var items: [Self] {
            var caseIndex: Int = 0
            let interator: AnyIterator<Self> = AnyIterator {
                let result = Self(rawValue: caseIndex)
                caseIndex += 1
                return result
            }
            return Array(interator)
        }
    }

    OriginalEl autor MonsterSale

  4. 3

    Simplemente añadir a la enumeración:
    static var allTypes: [Sections] = [.Section0, .Section1, .Section2]

    Y que puede:

    Sections.allTypes.forEach { (section) in
                print("\(section)")
    }

    OriginalEl autor Сергей Билык

  5. 1

    Iterada sobre las soluciones descritas anteriormente, vea a continuación un protocolo que puede ser implementado por las enumeraciones para agregar el allValues secuencia, pero también para permitir la posibilidad de convertir a y desde la cadena de valor.

    Muy conveniente para la Cadena-como las enumeraciones que necesita para apoyar el objetivo c (sólo int enumeraciones son permitidos).

    public protocol ObjcEnumeration: LosslessStringConvertible, RawRepresentable where RawValue == Int {
        static var allValues: AnySequence<Self> { get }
    }
    
    public extension ObjcEnumeration {
        public static var allValues: AnySequence<Self> {
            return AnySequence {
                return IntegerEnumIterator()
            }
        }
    
        public init?(_ description: String) {
            guard let enumValue = Self.allValues.first(where: { $0.description == description }) else {
                return nil
            }
            self.init(rawValue: enumValue.rawValue)
        }
    
        public var description: String {
            return String(describing: self)
        }
    }
    
    fileprivate struct IntegerEnumIterator<T: RawRepresentable>: IteratorProtocol where T.RawValue == Int {
        private var index = 0
        mutating func next() -> T? {
            defer {
                index += 1
            }
            return T(rawValue: index)
        }
    }

    Para un ejemplo concreto:

    @objc
    enum Fruit: Int, ObjcEnumeration {
        case apple, orange, pear
    }

    Ahora usted puede hacer:

    for fruit in Fruit.allValues {
    
        //Prints: "apple", "orange", "pear"
        print("Fruit: \(fruit.description)")
    
        if let otherFruit = Fruit(fruit.description), fruit == otherFruit {
            print("Fruit could be constructed successfully from its description!")
        }
    }

    OriginalEl autor Werner Altewischer

  6. 1

    Si su enumeración es un tipo Int basada en uno, usted puede hacer un efectivo pero un poco sucio truco como este.

    enum MyEnum: Int {
        case One
        case Two
    }
    
    extension MyEnum {
        func static allCases() -> [MyEnum] {
            var allCases = [MyEnum]()
            for i in 0..<10000 {
                if let type = MyEnum(rawValue: i) {
                    allCases.append(type)
                } else {
                    break
                }
            }
            return allCases
        }
    }

    A continuación, recorrer MyEnum.allCases()..

    OriginalEl autor Mike S

Dejar respuesta

Please enter your comment!
Please enter your name here