Я попытался свести эту проблему к простейшей форме следующим образом.
Настроить
Xcode версии 6.1.1 (6A2008a)
Перечисление, определенное в 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
}
}
}
и код, который инициализирует перечисление в другом файле 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")
}
}
ошибка
Xcode выдает следующую ошибку при попытке инициализации MyEnum
с помощью инициализатора необработанного значения:
Cannot convert the expression's type '(rawValue: IntegerLiteralConvertible)' to type 'MyEnum?'
Ноты
Согласно Swift Language Guide :
Если вы определяете перечисление с типом необработанного значения, перечисление автоматически получает инициализатор, который принимает значение типа необработанного значения (как вызываемый параметр
rawValue
) и возвращает либо член перечисления, либоnil
.Пользовательский инициализатор для
MyEnum
был определен в расширении, чтобы проверить, удалялся ли инициализатор необработанного значения перечисления из-за следующего случая из Language Guide . Однако он дает тот же результат ошибки.Обратите внимание: если вы определяете настраиваемый инициализатор для типа значения, у вас больше не будет доступа к инициализатору по умолчанию (или поэлементному инициализатору, если это структура) для этого типа. [...]
Если вы хотите, чтобы ваш настраиваемый тип значения был инициализирован с помощью инициализатора по умолчанию и поэлементного инициализатора, а также с вашими собственными настраиваемыми инициализаторами, напишите свои настраиваемые инициализаторы в расширении, а не как часть исходной реализации типа значения.Перемещение определения перечисления для
MyClass.swift
устранения ошибки для,bar
но не дляfoo
.Удаление настраиваемого инициализатора устраняет обе ошибки.
Один из способов обхода - включить следующую функцию в определение перечисления и использовать ее вместо предоставленного инициализатора необработанного значения. Таким образом, кажется, что добавление настраиваемого инициализатора имеет тот же эффект, что и маркировка инициализатора необработанного значения
private
.init?(raw: Int) { self.init(rawValue: raw) }
Явное объявление соответствия протокола
RawRepresentable
inMyClass.swift
разрешает встроенную ошибку дляbar
, но приводит к ошибке компоновщика, связанной с повторяющимися символами (поскольку перечисления типов с необработанными значениями неявно соответствуютRawRepresentable
).extension MyEnum: RawRepresentable {}
Может ли кто-нибудь дать немного больше информации о том, что здесь происходит? Почему недоступен инициализатор необработанного значения?
internal
область видимости (или, по крайней мере, соответствовать типу), а неprivate
.Ответы:
Эта ошибка решена в Xcode 7 и Swift 2.
источник
В вашем случае это приведет к следующему расширению:
источник
Вы даже можете сделать код более простым и полезным без
switch
кейсов, таким образом вам не нужно будет добавлять кейсы при добавлении нового типа.источник
Да, это неприятная проблема. В настоящее время я работаю над этим, используя функцию глобального масштаба, которая действует как фабрика, т.е.
источник
Это работает для Swift 4 на Xcode 9.2 вместе с моей EnumSequence :
Вывод
источник
Добавьте это в свой код:
источник