Как перехватить неверный список в swift - PullRequest
0 голосов
/ 27 января 2019

Я использую C для приведения своих полезных нагрузок по проводам, поэтому преобразование int в enum в c:

typedef CF_ENUM( uint8_t, MyEnum_t ) {
    a = 0
    b = 1
}
...
value = ( MyEnum_t * ) rawValue;

Поскольку значение по проводной связи, фактическое необработанное значение может быть любымuint8_t.Возможно, что rawValue на самом деле не равно 0 или 1.

Ниже приведен пример быстрого кода, показывающий установку перечисления на невозможное / недопустимое значение и оператор switch, обрабатывающий это значение.

import Foundation

enum MyEnum: UInt8 {
    case a = 0
    case b = 1
}

let raw: UInt8 = 0b100 // 4
let value: MyEnum = unsafeBitCast(raw, to: MyEnum.self)

switch value {
case .a:
    print("a:", value) // * not reached *
case .b:
    print("b:", value) // "b: \n"
    print("value == .a => \(value == .a)") // "x == .a => true\n"
    print("value == .b => \(value == .b)") // "x == .b => false\n"
}

print(value.rawValue) // "0"

При быстром значении C, равном 4, быстрый образец показывает сумасшедшие результаты:

  • 4, приведенное к силе, ничего не печатает для своего значения (скорее всего, символы 4 или 0, оба непечатаемые)
  • 4 переключается, поскольку MyEnum.b (1)
  • 4 сравнивается в равной степени с MyEnum.a (0)
  • 4, поскольку необработанное значение MyEnum выводит 0 (MyEnum.a)

Есть ли способ зафиксировать эту ошибку в swift?Я предпочитаю не использовать эти странные результаты для выявления аномалии.

1 Ответ

0 голосов
/ 27 января 2019

Название функций unsafeBitCast говорит само за себя.Более того, в документации четко сказано:

Предупреждение Вызов этой функции нарушает гарантии системы типа Swift;используйте с особой осторожностью.

Определенно не следует полагаться на внутреннюю реализацию перечисления в Swift, так как она может измениться.Вы должны обрабатывать особые случаи стандартными способами.Возможно, вы могли бы просто добавить пользовательский инициализатор:

import Foundation

enum MyEnum: UInt8 {
    case a = 0
    case b = 1

    init(fromWire value: UInt8) {                  // handle unusual input here
            self = value == 0 ? .a : .b
    }
}

// Test how it works
let arr: [UInt8] = [0, 1, 4]
for raw in arr {
    print("Input:", raw)
    let value = MyEnum(fromWire: raw)
    print("Value: \(value), raw enum value: \(value.rawValue)")
    if value==MyEnum.a { print("value == .a") }
    if value==MyEnum.b { print("value == .b") }
    switch value {
    case .a: print("case .a")
    case .b: print("case .b")
    }
    print()
}

Вывод:

Input: 0
Value: a, raw enum value: 0
value == .a
case .a

Input: 1
Value: b, raw enum value: 1
value == .b
case .b

Input: 4
Value: b, raw enum value: 1
value == .b
case .b
...