web-dev-qa-db-fra.com

Xcode 9 et Xcode 10 donnant des résultats différents, même avec la même version de Swift

J'utilise ce code dans les jeux xcode 9.3 et xcode 10 beta 3

import Foundation

public protocol EnumCollection: Hashable {
    static func cases() -> AnySequence<Self>
}

public extension EnumCollection {

    public static func cases() -> AnySequence<Self> {
        return AnySequence { () -> AnyIterator<Self> in
            var raw = 0
            return AnyIterator {
                let current: Self = withUnsafePointer(to: &raw) { $0.withMemoryRebound(to: self, capacity: 1) { $0.pointee } }

                guard current.hashValue == raw else {
                    return nil
                }

                raw += 1
                return current
            }
        }
    }
}

enum NumberEnum: EnumCollection{
    case one, two, three, four
}

Array(NumberEnum.cases()).count

même si les deux utilisent Swift 4.1, ils me donnent des résultats différents pour le 

sur xcode 9.3 la taille du tableau est 4

et sur xcode 10 beta 3 la taille du tableau est 0

Je ne comprends pas du tout.

10
kr15hna

C'est un moyen non documenté d'obtenir une séquence de toutes les valeurs d'énumération, Et qui n'a fonctionné que par hasard avec les versions antérieures de Swift. Il s’appuie sur les valeurs de hachage Des valeurs d’énumération étant des entiers consécutifs, Commençant à zéro.

Cela ne fonctionne définitivement plus avec Swift 4.2 (même s’il est en cours d’exécutionEn mode de compatibilité Swift 4) car les valeurs de hachage sont désormais toujours Randomisées, voir SE-0206 Hashable Enhancements :

Pour rendre les valeurs de hachage moins prévisibles, la fonction de hachage standard utilise un germe aléatoire par exécution par défaut.

Vous pouvez vérifier cela avec

print(NumberEnum.one.hashValue)
print(NumberEnum.two.hashValue)

qui not affiche 0 et 1 avec Xcode 10, mais quelques autres valeurs, qui varient également à chaque exécution du programme.

Pour une solution appropriée de Swift 4.2/Xcode 10, voir Comment énumérer une énumération avec le type String? :

extension NumberEnum: CaseIterable  { }
print(Array(NumberEnum.allCases).count) // 4
18
Martin R

La solution à cela est la suivante pour Xcode 10 et Swift 4.2 et supérieur.

Étape 1: Create Protocol EnumIterable.

protocol EnumIterable: RawRepresentable, CaseIterable {
    var indexValue: Int { get }
}

extension EnumIterable where Self.RawValue: Equatable {
    var indexValue: Int {
        var index = -1
        let cases = Self.allCases as? [Self] ?? []
        for (caseIndex, caseItem) in cases.enumerated() {
            if caseItem.rawValue == self.rawValue {
                index = caseIndex
                break
            }
        }
        return index
    }
}

Étape 2: Étendez le protocole EnumIterator à vos énumérations.

enum Colors: String, EnumIterable {
    case red = "Red"
    case yellow = "Yellow"
    case blue = "Blue"
    case green = "Green"
}

Étape 3: Utilisez la propriété indexValue comme avec hashValue.

Colors.red.indexValue
Colors.yellow.indexValue
Colors.blue.indexValue
Colors.green.indexValue

Exemple d'instruction d'impression et de sortie

print("Index Value: \(Colors.red.indexValue), Raw Value: \(Colors.red.rawValue), Hash Value: \(Colors.red.hashValue)")

Sortie: "Valeur d'index: 0, Valeur brute: Rouge, Valeur de hachage: 1593214705812839748"

print("Index Value: \(Colors.yellow.indexValue), Raw Value: \(Colors.yellow.rawValue), Hash Value: \(Colors.yellow.hashValue)")

Sortie: "Valeur d'index: 1, Valeur brute: Jaune, Valeur de hachage: -6836447220368660818"

print("Index Value: \(Colors.blue.indexValue), Raw Value: \(Colors.blue.rawValue), Hash Value: \(Colors.blue.hashValue)")

Sortie: "Valeur d'index: 2, Valeur brute: Bleu, Valeur de hachage: -8548080225654293616"

print("Index Value: \(Colors.green.indexValue), Raw Value: \(Colors.green.rawValue), Hash Value: \(Colors.green.hashValue)") 

Sortie: "Valeur d'index: 3, Valeur brute: Vert, Valeur de hachage: 6055121617320138804"

0
Amit Gajjar