Проблема в том, что соответствие Codable
в настоящее время может правильно обрабатывать только клавиши String
и Int
. Для словаря с любым другим типом Key
(где этот Key
равен Encodable
/ Decodable
), он кодируется и декодируется с помощью контейнера без ключа (массив JSON) со значениями чередующегося ключа. [1 134]
Поэтому при попытке декодировать JSON:
{"dictionary": {"enumValue": "someString"}}
в AStruct
значение ключа "dictionary"
, как ожидается, будет массивом.
Таким образом,
let jsonDict = ["dictionary": ["enumValue", "someString"]]
будет работать, давая JSON:
{"dictionary": ["enumValue", "someString"]}
, который затем будет декодирован в:
AStruct(dictionary: [AnEnum.enumValue: "someString"])
Однако, на самом деле я думаю, что Codable
соответствие [1120] должно быть способным правильно работать с любым CodingKey
соответствующим типом как его Key
(который может быть AnEnum
) - так как он может просто кодировать и с этим ключом декодировать в контейнер с ключами (не стесняйтесь подать запрос об ошибке )
До реализации (если это вообще возможно), мы всегда могли создать тип оболочки, чтобы сделать это:
struct CodableDictionary : Codable where Key : CodingKey {
let decoded: [Key: Value]
init(_ decoded: [Key: Value]) {
self.decoded = decoded
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: Key.self)
decoded = Dictionary(uniqueKeysWithValues:
try container.allKeys.lazy.map {
(key: [114], value: try container.decode(Value.self, forKey: [114]))
}
)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: Key.self)
for (key, value) in decoded {
try container.encode(value, forKey: key)
}
}
}
, а затем реализовать так:
enum AnEnum : String, CodingKey {
case enumValue
}
struct AStruct: Codable {
let dictionary: [AnEnum: String]
private enum CodingKeys : CodingKey {
case dictionary
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
dictionary = try container.decode(CodableDictionary.self, forKey: .dictionary).decoded
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(CodableDictionary(dictionary), forKey: .dictionary)
}
}
(или просто иметь свойство dictionary
типа CodableDictionary
и использовать автоматически сгенерированное соответствие Codable
- тогда просто поговорим в терминах dictionary.decoded
)
Теперь мы можем декодировать вложенный объект JSON, как и ожидалось:
let data = """
{"dictionary": {"enumValue": "someString"}}
""".data(using: .utf8)!
let decoder = JSONDecoder()
do {
let result = try decoder.decode(AStruct.self, from: data)
print(result)
} catch {
print(error)
}
// AStruct(dictionary: [AnEnum.enumValue: "someString"])
Несмотря на все сказанное, можно утверждать, что все, чего вы достигнете с помощью словаря с enum
в качестве ключа, это просто struct
с дополнительными свойствами (и если вы ожидайте, что данное значение всегда будет там, сделайте его необязательным).
Поэтому вы можете просто захотеть, чтобы ваша модель выглядела следующим образом:
struct BStruct : Codable {
var enumValue: String?
}
struct AStruct: Codable {
private enum CodingKeys : String, CodingKey {
case bStruct = "dictionary"
}
let bStruct: BStruct
}
Что бы отлично работать с вашим текущим JSON:
let data = """
{"dictionary": {"enumValue": "someString"}}
""".data(using: .utf8)!
let decoder = JSONDecoder()
do {
let result = try decoder.decode(AStruct.self, from: data)
print(result)
} catch {
print(error)
}
// AStruct(bStruct: BStruct(enumValue: Optional("someString")))
Простейший подход - использовать функцию atoi ()
, найденную в stdlib.h
:
CString s = "123";
int x = atoi( s );
Однако это плохо работает с случай, когда строка не содержит действительного целого числа, и в этом случае вам следует изучить функцию strtol ()
:
CString s = "12zzz"; // bad integer
char * p;
int x = strtol ( s, & p, 10 );
if ( * p != 0 ) {
// s does not contain an integer
}
CString s;
int i;
i = _wtoi(s); // if you use wide charater formats
i = _atoi(s); // otherwise
вы также можете использовать старый добрый sscanf.
CString s;
int i;
int j = _stscanf(s, _T("%d"), &i);
if (j != 1)
{
// tranfer didn't work
}
Если вы используете TCHAR.H
рутину (неявно или явно), убедитесь, что вы используете _ttoi()
функцию, чтобы она компилировалась как для Unicode, так и для ANSI компиляции.
Подробнее: https://msdn.microsoft.com/en-us/library/yd5xkb5c.aspx