Ich habe versucht, dieses Problem mit den folgenden Worten auf die einfachste Form zu bringen.
Konfiguration
Xcode Version 6.1.1 (6A2008a)
Eine Aufzählung definiert in 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
}
}
}
und Code, der die Aufzählung in einer anderen Datei initialisiert 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")
}
}
Error
Xcode gibt beim Versuch, MyEnum
mit seinem Rohwertinitialisierer zu initialisieren, den folgenden Fehler aus :
Cannot convert the expression's type '(rawValue: IntegerLiteralConvertible)' to type 'MyEnum?'
Anmerkungen
Gemäß dem Swift Language Guide :
Wenn Sie eine Aufzählung mit einem Rohwerttyp definieren, erhält die Aufzählung automatisch einen Initialisierer, der einen Wert des Rohwerttyps (als Parameter mit dem Namen
rawValue
) verwendet und entweder ein Aufzählungselement oder zurückgibtnil
.Der benutzerdefinierte Initialisierer für
MyEnum
wurde in einer Erweiterung definiert, um zu testen, ob der Rohwertinitialisierer der Enumeration aufgrund des folgenden Falls aus dem Sprachhandbuch entfernt wurde . Es wird jedoch das gleiche Fehlerergebnis erzielt.Beachten Sie, dass Sie, wenn Sie einen benutzerdefinierten Initialisierer für einen Werttyp definieren, keinen Zugriff mehr auf den Standardinitialisierer (oder den Mitgliedsinitialisierer, wenn es sich um eine Struktur handelt) für diesen Typ haben. [...]
Wenn Sie möchten, dass Ihr benutzerdefinierter Wertetyp mit dem Standardinitialisierer und dem Mitgliedsinitialisierer sowie mit Ihren eigenen benutzerdefinierten Initialisierern initialisiert werden kann, schreiben Sie Ihre benutzerdefinierten Initialisierer in eine Erweiterung und nicht als Teil der ursprünglichen Implementierung des Wertetyps.Durch Verschieben der Aufzählungsdefinition wird
MyClass.swift
der Fehler für,bar
jedoch nicht für behobenfoo
.Durch Entfernen des benutzerdefinierten Initialisierers werden beide Fehler behoben.
Eine Problemumgehung besteht darin, die folgende Funktion in die Aufzählungsdefinition aufzunehmen und anstelle des bereitgestellten Rohwertinitialisierers zu verwenden. Es scheint also, als hätte das Hinzufügen eines benutzerdefinierten Initialisierers einen ähnlichen Effekt wie das Markieren des Rohwertinitialisierers
private
.init?(raw: Int) { self.init(rawValue: raw) }
Das explizite Deklarieren der Protokollkonformität mit
RawRepresentable
inMyClass.swift
behebt den Inline-Fehler fürbar
, führt jedoch zu einem Linker-Fehler bei doppelten Symbolen (da Aufzählungen vom Typ Rohwert implizit übereinstimmenRawRepresentable
).extension MyEnum: RawRepresentable {}
Kann jemand etwas mehr Einblick in das geben, was hier vor sich geht? Warum ist der Rohwertinitialisierer nicht verfügbar?
internal
Gültigkeitsbereich haben (oder zumindest dem Typ entsprechen), nichtprivate
.