사용자 지정 이니셜 라이저가있는 Swift 열거 형에서 rawValue 이니셜 라이저가 손실 됨


95

나는이 문제를 다음과 같이 가장 단순한 형태로 요약하려고 노력했다.

설정

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?'

노트

  1. 스위프트 언어 가이드 :

    원시 값 유형으로 열거 형을 정의하는 경우 열거 형은 원시 값 유형의 값 (이라는 매개 변수)을 사용하는 이니셜 라이저를 자동으로 수신 rawValue하고 열거 형 멤버 또는 nil.

  2. 에 대한 사용자 정의 이니셜 MyEnum라이저는 언어 가이드 의 다음 사례로 인해 열거 형의 원시 값 이니셜 라이저가 제거되었는지 여부를 테스트하기 위해 확장에 정의되었습니다 . 그러나 동일한 오류 결과를 얻습니다.

    값 유형에 대해 사용자 정의 이니셜 라이저를 정의하면 해당 유형에 대한 기본 이니셜 라이저 (또는 구조 인 경우 멤버 단위 이니셜 라이저)에 더 이상 액세스 할 수 없습니다. [...]
    기본 이니셜 라이저 및 멤버 별 이니셜 라이저와 사용자 지정 이니셜 라이저를 사용하여 사용자 지정 값 형식을 초기화하려면 값 형식의 원래 구현의 일부가 아닌 확장에 사용자 지정 이니셜 라이저를 작성합니다.

  3. 열거 형 정의를 이동 MyClass.swift하면에 대한 오류 가 해결 bar되지만 foo.

  4. 사용자 지정 이니셜 라이저를 제거하면 두 오류가 모두 해결됩니다.

  5. 한 가지 해결 방법은 열거 형 정의에 다음 함수를 포함하고 제공된 원시 값 이니셜 라이저 대신 사용하는 것입니다. 따라서 사용자 지정 이니셜 라이저를 추가하면 원시 값 이니셜 라이저를 표시하는 것과 비슷한 효과가있는 것 같습니다 private.

    init?(raw: Int) {
        self.init(rawValue: raw)
    }
    
  6. RawRepresentablein에 MyClass.swift대한 프로토콜 적합성을 명시 적으로 선언 하면에 대한 인라인 오류가 해결 bar되지만 중복 기호에 대한 링커 오류가 발생합니다 (원시 값 유형 열거 형이 암시 적으로를 따르기 때문입니다 RawRepresentable).

    extension MyEnum: RawRepresentable {}

누구든지 여기서 무슨 일이 일어나고 있는지에 대해 조금 더 통찰력을 줄 수 있습니까? 원시 값 이니셜 라이저에 액세스 할 수없는 이유는 무엇입니까?


이 기본 이니셜 라이저에 버그를 신고해야합니다. 기본 이니셜 라이저 internal에는 private.
Nate Cook

나는 똑같은 문제가 있습니다. 나는 기본 하나를 초기화 사용자 정의를 만들면 것은 사라입니다
Yariv Nissim

나에게 벌레 냄새가 난다.
akashivskyy

2
내 의심을 확인해 주셔서 감사합니다. 이것은 버그로 신고되었습니다.
nickgraef

5 번이 저를 위해 해냈습니다.
Andrew Duncan

답변:


25

이 버그는 Xcode 7 및 Swift 2에서 해결되었습니다.


24
이러한 종류의 답변은 향후 방문자가 문제의 상태를 확인할 수 있도록 관련 티켓에 대한 링크를 통해 이익을 얻습니다.
Raphael

14
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
        }
    }
}

7

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
    }
}

1

예, 이것은 성가신 문제입니다. 저는 현재 공장 역할을하는 전역 범위 함수를 사용하여 작업하고 있습니다.

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
    }
}

0

이것은 내 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

-1

코드에 다음을 추가하십시오.

extension MyEnum {
    init?(rawValue: Int) {
        switch rawValue {
        case 0: self = .Zero
        case 1: self = .One
        case 2: self = .Two
        default: return nil
        }
    }
}

대신 Int를 확장 할 수 있습니까? 더 쉬운 것 같습니다.
ericgu
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.