Необязательная реализация var отличная, чистая, быстрая и идеально подходит для операторов guard let. Действительно убирает вызовы API.
Айрон Джон Бонни
22
Вот простые реализации DictionaryEncoder/ DictionaryDecoderчто обертка JSONEncoder, JSONDecoderи JSONSerialization, что также обрабатывать кодирования / декодирования стратегии ...
Большое спасибо! Альтернативой было бы использование наследования, но вызывающий сайт не смог бы вывести тип как словарь, так как было бы 2 функции с разными типами возврата.
user1046037
17
Я создал библиотеку под названием CodableFirebase, и ее первоначальной целью было использовать ее с базой данных Firebase, но она действительно делает то, что вам нужно: она создает словарь или любой другой тип, как в, JSONDecoderно вам не нужно делать здесь двойное преобразование как и в других ответах. Это будет выглядеть примерно так:
importCodableFirebaselet model =Foo(a:1, b:2)let dict =try!FirebaseEncoder().encode(model)
Это будет работать только для структур со всеми свойствами одного и того же типа
Лео Дабус
1
Я просто попробовал «let dict = try JSONDecoder (). Decode ([String: Int] .self, from: JSONEncoder (). Encode (foo))» и получил «Ожидается декодирование Dictionary <String, Any>, но обнаружил вместо этого массив ". не могли бы вы помочь,
Для этого нет встроенного способа. Как было сказано выше, если у вас нет проблем с производительностью, вы можете согласиться с реализацией JSONEncoder+ JSONSerialization.
Но я бы предпочел использовать стандартную библиотеку, чтобы предоставить объект кодировщика / декодера.
classDictionaryEncoder{privatelet jsonEncoder =JSONEncoder()/// Encodes given Encodable value into an array or dictionaryfunc encode<T>(_ value: T)throws->Anywhere T:Encodable{let jsonData =try jsonEncoder.encode(value)returntryJSONSerialization.jsonObject(with: jsonData, options:.allowFragments)}}classDictionaryDecoder{privatelet jsonDecoder =JSONDecoder()/// Decodes given Decodable type from given array or dictionaryfunc decode<T>(_ type: T.Type, from json:Any)throws-> T where T:Decodable{let jsonData =tryJSONSerialization.data(withJSONObject: json, options:[])returntry jsonDecoder.decode(type, from: jsonData)}}
Я определенно думаю, что есть некоторая ценность в том, чтобы просто использовать Codableдля кодирования в / из словарей, без намерения когда-либо нажимать JSON / Plists / что-то еще. Существует множество API, которые просто возвращают вам словарь или ожидают словарь, и приятно иметь возможность легко обмениваться ими с помощью структур или объектов Swift без необходимости писать бесконечный шаблонный код.
Я играл с некоторым кодом, основанным на исходном коде Foundation JSONEncoder.swift (который на самом деле реализует кодирование / декодирование словаря внутри, но не экспортирует его).
Это все еще довольно грубо, но я немного расширил его, чтобы, например, он мог заполнять отсутствующие значения значениями по умолчанию при декодировании.
Я изменил PropertyListEncoder из проекта Swift в DictionaryEncoder, просто удалив окончательную сериализацию из словаря в двоичный формат. Вы можете сделать то же самое или взять мой код отсюда
Я написал краткую суть, чтобы справиться с этим (без использования протокола Codable). Будьте осторожны, он не проверяет типы значений и не работает рекурсивно с кодируемыми значениями.
В Codable нет прямого способа сделать это. Вам необходимо реализовать протокол Encodable / Decodable для вашей структуры. Для вашего примера вам может потребоваться написать, как показано ниже
Если подумать, у этого вопроса нет ответа в общем случае, поскольку Encodableэкземпляр может быть чем-то не сериализуемым в словарь, например массивом:
let payload =[1,2,3]let encoded =tryJSONEncoder().encode(payload)//"[1,2,3]"
Ответы:
Если вы не против небольшого смещения данных, вы можете использовать что-то вроде этого:
Или дополнительный вариант
Если предположить,
Foo
что этоCodable
действительно так,Encodable
то вы можете это сделать.Если вы хотите пойти другим путем (
init(any)
), взгляните на этот Init объект, соответствующий Codable, со словарем / массивомисточник
Вот простые реализации
DictionaryEncoder
/DictionaryDecoder
что оберткаJSONEncoder
,JSONDecoder
иJSONSerialization
, что также обрабатывать кодирования / декодирования стратегии ...Использование аналогично
JSONEncoder
/JSONDecoder
…и
Для удобства я поместил все это в репо… https://github.com/ashleymills/SwiftDictionaryCoding
источник
Я создал библиотеку под названием CodableFirebase, и ее первоначальной целью было использовать ее с базой данных Firebase, но она действительно делает то, что вам нужно: она создает словарь или любой другой тип, как в,
JSONDecoder
но вам не нужно делать здесь двойное преобразование как и в других ответах. Это будет выглядеть примерно так:источник
Я не уверен, что это лучший способ, но вы определенно можете сделать что-то вроде:
источник
let dict = try JSONSerialization.jsonObject(with: try JSONEncoder().encode(struct), options: []) as? [String: Any]
источник
Для этого нет встроенного способа. Как было сказано выше, если у вас нет проблем с производительностью, вы можете согласиться с реализацией
JSONEncoder
+JSONSerialization
.Но я бы предпочел использовать стандартную библиотеку, чтобы предоставить объект кодировщика / декодера.
Вы можете попробовать это со следующим кодом:
Я пытаюсь сделать пример короче. В производственном коде вы должны соответствующим образом обрабатывать ошибки.
источник
В каком-то проекте я использовал быстрое отражение. Но будьте осторожны, вложенные кодируемые объекты также не отображаются там.
источник
Я определенно думаю, что есть некоторая ценность в том, чтобы просто использовать
Codable
для кодирования в / из словарей, без намерения когда-либо нажимать JSON / Plists / что-то еще. Существует множество API, которые просто возвращают вам словарь или ожидают словарь, и приятно иметь возможность легко обмениваться ими с помощью структур или объектов Swift без необходимости писать бесконечный шаблонный код.Я играл с некоторым кодом, основанным на исходном коде Foundation JSONEncoder.swift (который на самом деле реализует кодирование / декодирование словаря внутри, но не экспортирует его).
Код можно найти здесь: https://github.com/elegantchaos/DictionaryCoding
Это все еще довольно грубо, но я немного расширил его, чтобы, например, он мог заполнять отсутствующие значения значениями по умолчанию при декодировании.
источник
Я изменил PropertyListEncoder из проекта Swift в DictionaryEncoder, просто удалив окончательную сериализацию из словаря в двоичный формат. Вы можете сделать то же самое или взять мой код отсюда
Его можно использовать так:
источник
Я написал краткую суть, чтобы справиться с этим (без использования протокола Codable). Будьте осторожны, он не проверяет типы значений и не работает рекурсивно с кодируемыми значениями.
источник
В Codable нет прямого способа сделать это. Вам необходимо реализовать протокол Encodable / Decodable для вашей структуры. Для вашего примера вам может потребоваться написать, как показано ниже
источник
Я сделал стручок здесь https://github.com/levantAJ/AnyCodable для облегчения декодирования и кодирования
[String: Any]
и[Any]
И вы можете декодировать и кодировать
[String: Any]
и[Any]
источник
Если вы используете SwiftyJSON , вы можете сделать что-то вроде этого:
JSON(data: JSONEncoder().encode(foo)).dictionaryObject
источник
Вот решение на основе протокола:
И вот как им пользоваться:
источник
Вот словарь -> объект. Свифт 5.
источник
Если подумать, у этого вопроса нет ответа в общем случае, поскольку
Encodable
экземпляр может быть чем-то не сериализуемым в словарь, например массивом:Помимо этого, я написал нечто подобное в качестве фреймворка .
источник