Как инициализировать UIKeyboardType с помощью строки?

#swift #swiftui #uitextfield #uikeyboardtype

#swift #swiftui #uitextfield uitextfield #uikeyboardtype uikeyboardtype

Вопрос:

У меня есть структура jsondata, которая создается из файла JSON, который содержит это :

 {
  inputFieldTitle: "Total Cost",
  keyboardType: "numberPad"
}
 

В моем коде, как я могу использовать атрибут keyboardType для инициализации перечисления UIKeyboardType, чтобы установить тип клавиатуры в моем текстовом поле?

Обычно мы делаем это, чтобы получить цифровую клавиатуру (SwiftUI). :

 TextField(jsondata.inputFieldTitle) { ... }
  .keyboardType(.numberPad)
 

Но в моем сценарии я не могу жестко задать keyboardType с помощью .NumberPad, я должен использовать то, что указано в jsondata, как я могу использовать это значение для установки keyboardType в текстовом поле? Это, очевидно, не работает, потому что UIKeyboardType имеет тип Int :

 TextField(jsondata.inputFieldTitle) { ... }
  .keyboardType(UIKeyboardType(rawValue: jsondata.keyboardType))
 

Есть какие-нибудь советы? Спасибо.

Комментарии:

1. Почему бы вам не создать функцию, которая преобразует вашу строку в требуемый Int для перечисления?

2. Это может быть решением, но мне было интересно, есть ли более простой способ?

3. Вы используете свою собственную конструкцию для типа клавиатуры, вам нужно преобразовать ее в требуемый тип, самый простой способ — создать функцию, которая выполняет преобразование, или вы могли бы сделать что-то вроде того, что предложил Аспери

Ответ №1:

Вы можете привести UIKeyboardType в соответствие с Decodable и реализовать свой собственный метод декодирования:

 extension UIKeyboardType: Decodable {
    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        do {
            let rawValue = try container.decode(Int.self)
            guard let keyboardType = UIKeyboardType(rawValue: rawValue) else {
                throw DecodingError.dataCorruptedError(in: container, debugDescription: "invalid UIKeyboardType rawValue: (rawValue)")
            }
            self = keyboardType
        } catch DecodingError.typeMismatch {
            let string = try container.decode(String.self)
            guard let keyboardType = UIKeyboardType(string) else {
                throw DecodingError.dataCorruptedError(in: container, debugDescription: "invalid UIKeyboardType string: (string)")
            }
            self = keyboardType
        }
    }
    init?(_ string: String) {
        switch string {
        case "default":                 self = .default
        case "asciiCapable":            self = .asciiCapable
        case "numbersAndPunctuation":   self = .numbersAndPunctuation
        case "URL":                     self = .URL
        case "numberPad":               self = .numberPad
        case "phonePad":                self = .phonePad
        case "namePhonePad":            self = .namePhonePad
        case "emailAddress":            self = .emailAddress
        case "decimalPad":              self = .decimalPad
        case "twitter":                 self = .twitter
        case "webSearch":               self = .webSearch
        case "asciiCapableNumberPad":   self = .asciiCapableNumberPad
        case "alphabet":                self = .alphabet
        default: return nil
        }
    }
}
 

 extension UIKeyboardType: Encodable {
    public func encode(to encoder: Encoder) throws {
        var encoder = encoder.singleValueContainer()
        let string: String
        switch self {
        case .default:                 string = "default"
        case .asciiCapable:            string = "asciiCapable"
        case .numbersAndPunctuation:   string = "numbersAndPunctuation"
        case .URL:                     string = "URL"
        case .numberPad:               string = "numberPad"
        case .phonePad:                string = "phonePad"
        case .namePhonePad:            string = "namePhonePad"
        case .emailAddress:            string = "emailAddress"
        case .decimalPad:              string = "decimalPad"
        case .twitter:                 string = "twitter"
        case .webSearch:               string = "webSearch"
        case .asciiCapableNumberPad:   string = "asciiCapableNumberPad"
        }
        try encoder.encode(string)
    }
}
 

 extension DataProtocol {
    var string: String? { String(bytes: self, encoding: .utf8) }
}
 


Тестирование игровой площадки:

 struct Test: Codable {
    let inputFieldTitle: String
    let keyboardType: UIKeyboardType
}
 

 let numberPadJSON = """
{
  "inputFieldTitle": "Total Cost",
  "keyboardType": "numberPad"
}
"""
 

 do {
    let test = try JSONDecoder().decode(Test.self, from: Data(numberPadJSON.utf8))
    print(test.keyboardType.rawValue)  // 4
    let encoded = try JSONEncoder().encode(test)
    print(encoded.string ?? "")  // {"inputFieldTitle":"Total Cost","keyboardType":"numberPad"}
} catch {
    print(error)
}
 

Комментарии:

1. Это довольно аккуратно, так как моя структура jsondata поддается кодированию, поэтому это решение работает как по волшебству.

2. Я видел, что вы перешли с Кодируемого на Декодируемый. Почему вы решили внести это изменение и каков его эффект? Моя структура поддается кодированию, поэтому кодируемое решение было аккуратным.

3. Вы можете сохранить его кодируемым, если захотите. Если вам нужно его закодировать, просто убедитесь, что вы также внедрили часть кодирования, чтобы сохранить ее согласованной, иначе она будет кодироваться как Int.

Ответ №2:

UIKeyboardType is-a Int , поэтому вы не можете использовать rawValue , потому что ваше значение json является строковым.

Вот возможное решение

 extension UIKeyboardType {
    static private let types = ["numberPad": numberPad]   // << extend to all supported
    init(_ value: String) {
        if let result = Self.types[value] {
            self = result
        } else {
            self = .default
        }
    }
}
 

и теперь вы можете использовать его как

 TextField(jsondata.inputFieldTitle) { ... }
  .keyboardType(UIKeyboardType(jsondata.keyboardType))
//  .keyboardType(UIKeyboardType(jsondata.keyboardType ?? "")) // if optional
 

Комментарии:

1. Почему не просто ["numberPad": numberPad] ? types уже является статическим свойством UIKeyboardType . Self. является избыточным.