J’ai essayé de résumer ce problème dans sa forme la plus simple avec ce qui suit.
Xcode Version 6.1.1 (6A2008a)
Une énumération définie dans MyEnum.swift
:
internal enum MyEnum: Int { case Zero = 0, One, Two } extension MyEnum { init?(ssortingng: Ssortingng) { switch ssortingng.lowercaseSsortingng { case "zero": self = .Zero case "one": self = .One case "two": self = .Two default: return nil } } }
et code qui initialise l’énumération dans un autre fichier, MyClass.swift
:
internal class MyClass { let foo = MyEnum(rawValue: 0) // Error let fooStr = MyEnum(ssortingng: "zero") func testFunc() { let bar = MyEnum(rawValue: 1) // Error let barStr = MyEnum(ssortingng: "one") } }
Xcode me donne l’erreur suivante lors de la tentative d’initialisation de MyEnum
avec son initialiseur de valeur brute:
Cannot convert the expression's type '(rawValue: IntegerLiteralConvertible)' to type 'MyEnum?'
Selon le guide linguistique Swift :
Si vous définissez une énumération avec un type de valeur brute, l’énumération reçoit automatiquement un initialiseur qui prend une valeur du type de la valeur brute (en tant que paramètre appelé
rawValue
) et retourne un membre d’énumération ounil
.
L’initialiseur personnalisé pour MyEnum
été défini dans une extension pour tester si l’initialiseur de valeur brute de l’énum a été supprimé en raison du cas suivant du Guide de langue . Cependant, il obtient le même résultat d’erreur.
Notez que si vous définissez un initialiseur personnalisé pour un type de valeur, vous n’aurez plus access à l’initialiseur par défaut (ou à l’initialiseur par membre, s’il s’agit d’une structure) pour ce type. […]
Si vous souhaitez que votre type de valeur personnalisé puisse être initialisé avec l’initialiseur par défaut et l’initialiseur selon les membres, ainsi qu’avec vos propres initialiseurs personnalisés, écrivez vos initialiseurs personnalisés dans une extension plutôt que dans l’implémentation d’origine du type de valeur.
Déplacer la définition enum dans MyClass.swift
résout l’erreur pour la bar
mais pas pour foo
.
La suppression de l’initialiseur personnalisé résout les deux erreurs.
Une solution consiste à inclure la fonction suivante dans la définition enum et à l’utiliser à la place de l’initialiseur de valeur brute fourni. Il semble donc que l’ajout d’un initialiseur personnalisé ait le même effet que le marquage private
initialiseur à valeur brute.
init?(raw: Int) { self.init(rawValue: raw) }
La déclaration explicite de la conformité du protocole à RawRepresentable
dans MyClass.swift
résout l’erreur en ligne pour bar
, mais entraîne une erreur de l’éditeur de liens à propos des symboles en double (car les RawRepresentable
type valeur brute implicitement conformes à RawRepresentable
).
extension MyEnum: RawRepresentable {}
Quelqu’un peut-il donner un petit aperçu de ce qui se passe ici? Pourquoi l’initialiseur de valeur brute n’est-il pas accessible?
Ce bogue est résolu dans Xcode 7 et Swift 2
extension TemplateSlotType { init?(rawSsortingng: Ssortingng) { // Check if ssortingng contains 'carrousel' if rawSsortingng.rangeOfSsortingng("carrousel") != nil { self.init(rawValue:"carrousel") } else { self.init(rawValue:rawSsortingng) } } }
Dans votre cas, cela entraînerait l’extension suivante:
extension MyEnum { init?(ssortingng: Ssortingng) { switch ssortingng.lowercaseSsortingng { case "zero": self.init(rawValue:0) case "one": self.init(rawValue:1) case "two": self.init(rawValue:2) default: return nil } } }
Vous pouvez même rendre le code plus simple et utile sans switch
cas, vous n’avez donc pas besoin d’append plus de cas lorsque vous ajoutez un nouveau type.
enum VehicleType: Int, CustomSsortingngConvertible { case car = 4 case moped = 2 case truck = 16 case unknown = -1 // MARK: - Helpers public var description: Ssortingng { switch self { case .car: return "Car" case .truck: return "Truck" case .moped: return "Moped" case .unknown: return "unknown" } } static let all: [VehicleType] = [car, moped, truck] init?(rawDescription: Ssortingng) { guard let type = VehicleType.all.first(where: { description == rawDescription }) else { return nil } self = type } }
Oui, c’est un problème ennuyeux. Je suis en train de le contourner en utilisant une fonction de scope globale qui agit comme une usine, c.-à-d.
func enumFromSsortingng(ssortingng:Ssortingng) -> MyEnum? { switch ssortingng { case "One" : MyEnum(rawValue:1) case "Two" : MyEnum(rawValue:2) case "Three" : MyEnum(rawValue:3) default : return nil } }
Cela fonctionne pour Swift 4 sur Xcode 9.2 avec mon EnumSequence :
enum Word: Int, EnumSequenceElement, CustomSsortingngConvertible { case apple, cat, fun var description: Ssortingng { switch self { case .apple: return "Apple" case .cat: return "Cat" case .fun: return "Fun" } } } let Words: [Ssortingng: Word] = [ "A": .apple, "C": .cat, "F": .fun ] extension Word { var letter: Ssortingng? { return Words.first(where: { (_, word) -> Bool in word == self })?.key } init?(_ letter: Ssortingng) { if let word = Words[letter] { self = word } else { return nil } } } for word in EnumSequence() { if let letter = word.letter, let lhs = Word(letter), let rhs = Word(letter), lhs == rhs { print("\(letter) for \(word)") } }
Sortie
A for Apple C for Cat F for Fun
Ajoutez ceci à votre code:
extension MyEnum { init?(rawValue: Int) { switch rawValue { case 0: self = .Zero case 1: self = .One case 2: self = .Two default: return nil } } }