Введение в json со свифтом. Часть 2.

Всем привет!
Как и было обещано в предыдущем посте, сегодня мы с вами распарсим JSON, но уже без сторонних библиотек, а руками. 😱
На самом деле, ужасно давно уже этого не делал. 😅
Хотя, наверное, зря. Иногда мы привыкаем, что для всего можно просто добавить очередную библиотеку и сделать все “быстро и просто”, хотя это лишние зависимости и вообще.
Поэтому, сегодня будут только методы из Foundation, только хардкор, поехали! 🚀
Для того, чтобы пройти этот туториал, вам понадобится Xcode beta 9 со swift 4 на борту, скачать ее можно, зарегистрировавшись на портале для разработчиков Apple, вот здесь. А также я подготовил стартовый и законченный проекты. Их можно скачать тут.
Итак, открываем стартовый playground project, и все, что мы там можем обнаружить, это
А еще там есть, если зайти в папку Resourses, test.json.
Читаем JSON
Для начала нам стоит этот json прочитать. Для этого необходимо создать метод getJSON.
Далее стоит добавить путь до JSON файла. Так как путь у нас будет optional, я раскрою его безопасным образом через if let. Можно сразу отметить, что так как мы уверены, что JSON существует, в этом нет большой необходимости, просто я так привык 😄
Далее стоит получить объект data из полученного пути. Для этого добавим do-catch блок, внутри которого получим объект data, а если получить его не получится, выведем ошибку.
Большая часть пути уже позади, осталось только получить из объекта data наш JSON, который в свифте описывается как [String: Any]. Для этого нам нужно вызвать привычный со времен Objective-C JSONSerialization на data:
Объединенный код будет выглядеть так (в конце просто вызовем этот метод):
Ура, мы получили json и можем видеть его содержимое в дебаггере 😄
Осталось добавить класс пользователя, чтобы распарсить его 🙃
Добавим класс User в наш Playground, и, могу обрадовать, этот класс не будет сильно отличаться от того, который мы написали в прошлый раз:
Собственно, все, что здесь действительно изменилось, так это то, что вместо типа JSON мы используем [String: Any]?.
Метод парсера тоже не особо изменился:
Изменения здесь только синтаксические, потому как .string в SwiftyJSON делал то же самое, что здесь делает as? String.
Осталось немного изменить наш getJSON в Playground. Для начала вернем пользователя.
Далее удаляем строку print(json) и добавляем вместо нее:
А если if let path не сработал, то просто вернем nil. Таким образом, наш метод приобретает следующий вид:
Осталось отпринтовать пользователя и поздравить себя с тем, что мы распарсили очередной JSON 🎉🎉🎉
Примерно так мы парсили JSON до всех этих наших хипстерских библиотек во времена старого доброго Objective-C. И каждый раз это выглядело немного странно и вообще akward. Мы получаем валидный JSON, превращаем его в Data, потом в [String: Any] (или в [String: AnyObject]), а потом в обработанный объект. И к релизу swift 4 Apple решил-таки ответить на вопрос, как они видят парсинг JSON.
Видят очень круто 😎
Пишем SwiftyParse
В том же playground файле создадим новый метод getSwiftyJSON(), туда перенесем наш if let path, do-catch блоки и data. Метод должен выглядеть так:
А теперь начинается магия Swift 4 🎩
Создадим объект decoder и добавим еще один do-catch блок:
Как можно догадаться, внутри этого do-catch блока мы и будем получать пользователя. Вот только происходить это будет совсем иначе 😁
Вот и все!
Осталось создать класс SwiftyUser, и попробуйте догадаться, в чем разница с предыдущим методом 🤔
Новый класс выглядит следующим образом:
И все, если мы захотим отпринтовать полученного пользователя, мы получим то же самое, что раньше делали через JSONSerialization.jsonObject!
При этом здесь нет никаких инициализаторов! (Можете проверить и добавить, метод init не вызывается.) Декодер сам пробегает по JSON файлу и сравнивает его с тем, что мы ему предлагаем в качестве объекта декодинга! Магия! 🎩
А как же быть со вложенными объектами?
Да прямо так и быть!
Как вы могли заметить, у нас там есть объект Location: Добавим его к SwiftyUser:
И вуаля, локация добавлена! Но, подождите, там же не хватает country.
И вот здесь кроется минус такого метода. Для каждого вложения, сообщает нам Apple, лучше создавать отдельный struct/class/enum. В данном случаем мы создадим countryObj:
Осталось вернуть пользователя. Для этого изменим метод следующим образом:
И отпринтуем пользователя, думаю, вы уже знаете, как это делать. 😏
Поздравляю, вы только что разобрались, как модно-хипстерски парсить JSON в Swift 4! 😎🎉🎉🎉🎉🎉🎉
Да, к этому новому методу нужно привыкнуть, но у него множество возможностей для кастомизации, пусть они и не всегда очевидные. А ведь это и правда круто — парсить json безо всех этих бесконечных if let. Или не круто 🤔
В любом случае, буду рад услышать мнение в комментах 😆
Ох, пост вышел несколько длиннее, чем планировалось, но, надеюсь, вам не было скучно, и вы узнали что-то новое. В любом случае, лайк-репост 😄
Photo by Luke Chesser on Unsplash
