나는이 문제를 다음과 같이 가장 단순한 형태로 요약하려고 노력했다.
설정
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?'
노트
-
당 스위프트 언어 가이드 :
원시 값 유형으로 열거 형을 정의하는 경우 열거 형은 원시 값 유형의 값 (이라는 매개 변수)을 사용하는 이니셜 라이저를 자동으로 수신
rawValue
하고 열거 형 멤버 또는nil
. -
에 대한 사용자 정의 이니셜
MyEnum
라이저는 언어 가이드 의 다음 사례로 인해 열거 형의 원시 값 이니셜 라이저가 제거되었는지 여부를 테스트하기 위해 확장에 정의되었습니다 . 그러나 동일한 오류 결과를 얻습니다.값 유형에 대해 사용자 정의 이니셜 라이저를 정의하면 해당 유형에 대한 기본 이니셜 라이저 (또는 구조 인 경우 멤버 단위 이니셜 라이저)에 더 이상 액세스 할 수 없습니다. […]
기본 이니셜 라이저 및 멤버 별 이니셜 라이저와 사용자 지정 이니셜 라이저를 사용하여 사용자 지정 값 형식을 초기화하려면 값 형식의 원래 구현의 일부가 아닌 확장에 사용자 지정 이니셜 라이저를 작성합니다. -
열거 형 정의를 이동
MyClass.swift
하면에 대한 오류 가 해결bar
되지만foo
. -
사용자 지정 이니셜 라이저를 제거하면 두 오류가 모두 해결됩니다.
-
한 가지 해결 방법은 열거 형 정의에 다음 함수를 포함하고 제공된 원시 값 이니셜 라이저 대신 사용하는 것입니다. 따라서 사용자 지정 이니셜 라이저를 추가하면 원시 값 이니셜 라이저를 표시하는 것과 비슷한 효과가있는 것 같습니다
private
.init?(raw: Int) { self.init(rawValue: raw) }
-
RawRepresentable
in에MyClass.swift
대한 프로토콜 적합성을 명시 적으로 선언 하면에 대한 인라인 오류가 해결bar
되지만 중복 기호에 대한 링커 오류가 발생합니다 (원시 값 유형 열거 형이 암시 적으로를 따르기 때문입니다RawRepresentable
).extension MyEnum: RawRepresentable {}
누구든지 여기서 무슨 일이 일어나고 있는지에 대해 조금 더 통찰력을 줄 수 있습니까? 원시 값 이니셜 라이저에 액세스 할 수없는 이유는 무엇입니까?
답변
이 버그는 Xcode 7 및 Swift 2에서 해결되었습니다.
답변
extension TemplateSlotType {
init?(rawString: String) {
// Check if string contains 'carrousel'
if rawString.rangeOfString("carrousel") != nil {
self.init(rawValue:"carrousel")
} else {
self.init(rawValue:rawString)
}
}
}
귀하의 경우에는 다음과 같은 확장이 발생합니다.
extension MyEnum {
init?(string: String) {
switch string.lowercaseString {
case "zero":
self.init(rawValue:0)
case "one":
self.init(rawValue:1)
case "two":
self.init(rawValue:2)
default:
return nil
}
}
}
답변
switch
케이스 없이 코드를 더 간단하고 유용하게 만들 수도 있습니다 . 이렇게하면 새 유형을 추가 할 때 케이스를 더 추가 할 필요가 없습니다.
enum VehicleType: Int, CustomStringConvertible {
case car = 4
case moped = 2
case truck = 16
case unknown = -1
// MARK: - Helpers
public var description: String {
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: String) {
guard let type = VehicleType.all.first(where: { description == rawDescription })
else { return nil }
self = type
}
}
답변
예, 이것은 성가신 문제입니다. 저는 현재 공장 역할을하는 전역 범위 함수를 사용하여 작업하고 있습니다.
func enumFromString(string:String) -> MyEnum? {
switch string {
case "One" : MyEnum(rawValue:1)
case "Two" : MyEnum(rawValue:2)
case "Three" : MyEnum(rawValue:3)
default : return nil
}
}
답변
이것은 내 EnumSequence 와 함께 Xcode 9.2의 Swift 4에서 작동합니다 .
enum Word: Int, EnumSequenceElement, CustomStringConvertible {
case apple, cat, fun
var description: String {
switch self {
case .apple:
return "Apple"
case .cat:
return "Cat"
case .fun:
return "Fun"
}
}
}
let Words: [String: Word] = [
"A": .apple,
"C": .cat,
"F": .fun
]
extension Word {
var letter: String? {
return Words.first(where: { (_, word) -> Bool in
word == self
})?.key
}
init?(_ letter: String) {
if let word = Words[letter] {
self = word
} else {
return nil
}
}
}
for word in EnumSequence<Word>() {
if let letter = word.letter, let lhs = Word(letter), let rhs = Word(letter), lhs == rhs {
print("\(letter) for \(word)")
}
}
산출
A for Apple
C for Cat
F for Fun
답변
코드에 다음을 추가하십시오.
extension MyEnum {
init?(rawValue: Int) {
switch rawValue {
case 0: self = .Zero
case 1: self = .One
case 2: self = .Two
default: return nil
}
}
}