Ho cercato di ridurre questo problema alla sua forma più semplice con quanto segue.
Impostare
Versione Xcode 6.1.1 (6A2008a)
Un enum definito 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
}
}
}
e il codice che inizializza l'enum in un altro file, 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")
}
}
Errore
Xcode mi dà il seguente errore quando tento di inizializzare MyEnum
con il suo inizializzatore di valori non elaborati:
Cannot convert the expression's type '(rawValue: IntegerLiteralConvertible)' to type 'MyEnum?'
Appunti
Secondo la Swift Language Guide :
Se si definisce un'enumerazione con un tipo di valore non elaborato, l'enumerazione riceve automaticamente un inizializzatore che accetta un valore del tipo di valore non elaborato (come un parametro chiamato
rawValue
) e restituisce un membro di enumerazione onil
.L'inizializzatore personalizzato per è
MyEnum
stato definito in un'estensione per verificare se l'inizializzatore del valore non elaborato dell'enumerazione veniva rimosso a causa del seguente caso dalla Guida alla lingua . Tuttavia, ottiene lo stesso risultato di errore.Si noti che se si definisce un inizializzatore personalizzato per un tipo di valore, non si avrà più accesso all'inizializzatore predefinito (o all'inizializzatore memberwise, se è una struttura) per quel tipo. [...]
Se desideri che il tuo tipo di valore personalizzato sia inizializzabile con l'inizializzatore predefinito e l'inizializzatore per i membri, e anche con i tuoi inizializzatori personalizzati, scrivi gli inizializzatori personalizzati in un'estensione piuttosto che come parte dell'implementazione originale del tipo di valore.Spostando la definizione dell'enumerazione su
MyClass.swift
risolve l'errore perbar
ma non perfoo
.La rimozione dell'inizializzatore personalizzato risolve entrambi gli errori.
Una soluzione alternativa consiste nell'includere la seguente funzione nella definizione di enum e utilizzarla al posto dell'inizializzatore di valori non elaborati fornito. Quindi sembra che l'aggiunta di un inizializzatore personalizzato abbia un effetto simile alla marcatura dell'inizializzatore di valori non elaborati
private
.init?(raw: Int) { self.init(rawValue: raw) }
Dichiarare esplicitamente la conformità del protocollo a
RawRepresentable
inMyClass.swift
risolve l'errore inline perbar
, ma si traduce in un errore del linker sui simboli duplicati (perché le enumerazioni del tipo di valore grezzo sono implicitamente conformi aRawRepresentable
).extension MyEnum: RawRepresentable {}
Qualcuno può fornire qualche informazione in più su cosa sta succedendo qui? Perché l'inizializzatore del valore grezzo non è accessibile?
internal
ambito (o almeno corrispondere al tipo), nonprivate
.