J'ai essayé de résumer ce problème à sa forme la plus simple avec ce qui suit.
Installer
Version 6.1.1 de Xcode (6A2008a)
Une énumération définie dans MyEnum.swift
:
internal enum MyEnum: Int {
case Zero = 0, One, Two
}
extension MyEnum {
init?(string: String) {
switch string.lowercaseString {
case "zero": self = .Zero
case "one": self = .One
case "two": self = .Two
default: return nil
}
}
}
et le code qui initialise le ENUM dans un autre fichier, MyClass.swift
:
internal class MyClass {
let foo = MyEnum(rawValue: 0) // Error
let fooStr = MyEnum(string: "zero")
func testFunc() {
let bar = MyEnum(rawValue: 1) // Error
let barStr = MyEnum(string: "one")
}
}
Erreur
Xcode me donne l'erreur suivante lors de la tentative d'initialisation MyEnum
avec son initialiseur de valeur brute:
Cannot convert the expression's type '(rawValue: IntegerLiteralConvertible)' to type 'MyEnum?'
Remarques
Par le guide du langage Swift :
Si vous définissez une énumération avec un type à 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 renvoie un membre d'énumération ounil
.L'initialiseur personnalisé pour a
MyEnum
été défini dans une extension pour tester si l'initialiseur de valeur brute de l'énumération a été supprimé en raison du cas suivant de Guide du langage . Cependant, il obtient le même résultat d'erreur.Notez que si vous définissez un initialiseur personnalisé pour un type valeur, vous n'aurez plus accès à l'initialiseur par défaut (ou à l'initialiseur par membre, s'il s'agit d'une structure) pour ce type. [...]
Si vous voulez que votre type de valeur personnalisé soit initialisable avec l'initialiseur par défaut et l'initialiseur par membre, ainsi qu'avec vos propres initialiseurs personnalisés, écrivez vos initialiseurs personnalisés dans une extension plutôt que dans le cadre de l'implémentation d'origine du type de valeur.Le déplacement de la définition d'énumération pour
MyClass.swift
résoudre l'erreur pourbar
mais pas pourfoo
.La suppression de l'initialiseur personnalisé résout les deux erreurs.
Une solution de contournement consiste à inclure la fonction suivante dans la définition d'énumération et à l'utiliser à la place de l'initialiseur de valeur brute fourni. Il semble donc que l'ajout d'un initialiseur personnalisé ait un effet similaire au marquage de l'initialiseur à valeur brute
private
.init?(raw: Int) { self.init(rawValue: raw) }
La déclaration explicite de la conformité du protocole à
RawRepresentable
dansMyClass.swift
résout l'erreur en ligne pourbar
, mais entraîne une erreur de l'éditeur de liens concernant les symboles en double (car les énumérations de type à valeur brute sont implicitement conformes àRawRepresentable
).extension MyEnum: RawRepresentable {}
Quelqu'un peut-il donner un peu plus d'informations sur ce qui se passe ici? Pourquoi l'initialiseur de valeur brute n'est-il pas accessible?
internal
portée (ou au moins correspondre au type), nonprivate
.Réponses:
Ce bogue est résolu dans Xcode 7 et Swift 2
la source
Dans votre cas, cela entraînerait l'extension suivante:
la source
Vous pouvez même rendre le code plus simple et utile sans
switch
cas, de cette façon, vous n'avez pas besoin d'ajouter plus de cas lorsque vous ajoutez un nouveau type.la source
Ouais, c'est un problème ennuyeux. Je travaille actuellement autour de lui en utilisant une fonction de portée globale qui agit comme une usine, c'est-à-dire
la source
Cela fonctionne pour Swift 4 sur Xcode 9.2 avec mon EnumSequence :
Production
la source
Ajoutez ceci à votre code:
la source