- PVSM.RU - https://www.pvsm.ru -
JavaScript Object Notation [1], или сокращенно JSON является самым распространенным способом связи с сервером и получения информации с него. Он чрезвычайно популярен из-за простоты в использовании и восприятии.
Рассмотрим следующий фрагмент JSON:
[
{
"person": {
"name": "Dani",
"age": "24"
}
},
{
"person": {
"name": "ray",
"age": "70"
}
}
]
В Objective-C, парсинг и десериализация JSON достаточно простая:
NSArray *json = [NSJSONSerialization JSONObjectWithData:JSONData options:kNilOptions error:nil];
NSString *age = json[0][@"person"][@"age"];
NSLog(@"Dani's age is %@", age);
В Swift, это более сложный процесс из-за опциональных (optionals) типов и типобезопасности:
var json: Array!
do {
json = try NSJSONSerialization.JSONObjectWithData(JSONData, options: NSJSONReadingOptions()) as? Array
} catch {
print(error)
}
if let item = json[0] as? [String: AnyObject] {
if let person = item["person"] as? [String: AnyObject] {
if let age = person["age"] as? Int {
print("Dani's age is (age)")
}
}
}
В представленном выше коде, необходимо проверять каждый объект до его использования optional binding. Это защитит ваш код; но чем сложнее JSON, тем более громоздким становится код.
В Swift 2.0, был введено оператор guard для того, чтобы избавиться от вложенных выражений if:
guard let item = json[0] as? [String: AnyObject],
let person = item["person"] as? [String: AnyObject],
let age = person["age"] as? Int else {
return;
}
print("Dani's age is (age)")
Все еще многословно? Но как это упростить?
В этой статье по работе с JSON используется простейший способ парсинга JSON – используя популярную общедоступную библиотеку Gloss [2].
Так, в частности вы будете использовать Gloss для парсинга и преобразования JSON, который вмещает в себе 25 популярных приложений в US App Store. Так же просто, как и в Objective-C!
Скачайте стартовый playground [3] для это статьй.
Поскольку пользовательский интерфейс не нужен, будем работать исключительно с playground'oм.
Откройте Swift.playground в Xcode и изучите его.
Заметка: Вы можете заметить, что Project Navigator по умолчанию закрыт. Если это так, нажмите Command+1 чтобы вывести его на экран. У вас должно получится так как на изображению ниже.
Стартовый файл playground вмещает несколько исходных и ресурсных файлов, которые полностью сосредоточены на парсинге JSON. Обратите внимание на структуру playground'a:
Как только вы разобрались в данном playground'e, продолжайте читать статью!
Во-первых, начнем с нативного способа парсинга JSON в Swift – то есть не используя внешних библиотек. С помощью этого, вы оцените преимущества использования такой библиотеки как Gloss.
Заметка: Если вы уже изучили недостатки нативного способа парсинга JSON и хотите перейти к Gloss, пропустите следующий абзац.
Чтобы дать название приложению #1 в App Store, разберем предоставленный JSON файл.
Перед тем как начать работу со словарями, задайте дополнительное имя (alias) вверху playground'a:
typealias Payload = [String: AnyObject]
Добавьте код обратного вызова getTopAppsDataFromFileWithSuccess как показано ниже:
DataManager.getTopAppsDataFromFileWithSuccess { (data) -> Void in
var json: Payload!
// 1
do {
json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as? Payload
} catch {
print(error)
XCPlaygroundPage.currentPage.finishExecution()
}
// 2
guard let feed = json["feed"] as? Payload,
let apps = feed["entry"] as? [AnyObject],
let app = apps.first as? Payload
else { XCPlaygroundPage.currentPage.finishExecution() }
guard let container = app["im:name"] as? Payload,
let name = container["label"] as? String
else { XCPlaygroundPage.currentPage.finishExecution() }
guard let id = app["id"] as? Payload,
let link = id["label"] as? String
else { XCPlaygroundPage.currentPage.finishExecution() }
// 3
let entry = App(name: name, link: link)
print(entry)
XCPlaygroundPage.currentPage.finishExecution()
}
Вот что происходит:
Сохраните и запустите playground; вы увидите следующее в консоли отладчика:
App(name: "Game of War - Fire Age", link: "https://itunes.apple.com/us/app/game-of-war-fire-age/id667728512?mt=8&uo=2")
Да — “Game of War – Fire Age” это приложение #1 в файле JSON.
Потребовалось довольно большое количество код для получения названия первого приложения – пора посмотреть, как с этим справится Gloss.
Преобразование объектов (Object mapping) представляет собой технику превращения объектов c JSON в объекты Swift. После определения моделей (model objects) и правил отображения (mapping rules), Gloss проделывает сложную работу исполняя вместо вас парсинг.
Этот способ значительно проще, чем тот, который вы использовали раньше:
Звучит неплохо, да? Посмотрим, как это работает!
Чтобы все выглядело безупречно, создайте новый playground Gloss.playground, затем скопируйте файл topapps.json в папку Resources и DataManager.swift и папку Sources.
Довольно просто внедрить Gloss в ваш проект:
Ваш Project Navigator должен выглядеть следующим образом:
Это всё! Теперь Gloss добавлен в ваш проект и вы можете начать разбор JSON без головной боли!
Заметка: Gloss можно установить так же через Cocoapods. Поскольку playground их пока не поддерживают, этот способ можно использовать только при работе с проектами.
Сначала выясните как ваш объект относится к вашему JSON документу.
Необходимо, чтобы объект соответствовала протоколу Decodeable, который может декодировать их с JSON. Чтобы сделать это, осуществите инициализацию init?(json: JSON) как сказано в протоколе.
Обратите внимание на структуру topapps.json и создайте модель данных.
TopApps
Модель TopApps представляет собой объект высшего уровня, который вмещает в себе одну пару ключ-значения (key-value)
{
"feed": {
...
}
}
Создайте новый файл с названием TopApps.swift и поместите его в папке Sources вашего playground'a; добавьте следующий код:
public struct TopApps: Decodable {
// 1
public let feed: Feed?
// 2
public init?(json: JSON) {
feed = "feed" <~~ json
}
}
Feed
Объект Feed очень похож на объект высшего уровня. У него есть две пары ключ-значения, но поскольку нам интересны только 25 популярных приложений, нет необходимости обрабатывать объект author.
{
"author": {
...
},
"entry": [
...
]
}
Создайте новый файл с названием Feed.swift в папке Sources вашего playground'a и опишите его следующим образом:
public struct Feed: Decodable {
public let entries: [App]?
public init?(json: JSON) {
entries = "entry" <~~ json
}
}
App
Самым последним объектом, который надо описать является объект App. Приложение представлено в виде такой схемы:
{
"im:name": {
"label": "Game of War - Fire Age"
},
"id": {
"label": "https://itunes.apple.com/us/app/game-of-war-fire-age/id667728512?mt=8&uo=2",
...
},
...
}
Создайте новый файл с названием App.swift в папке Sources вашего playground'a и добавьте следующий код:
public struct App: Decodable {
// 1
public let name: String
public let link: String
public init?(json: JSON) {
// 2
guard let container: JSON = "im:name" <~~ json,
let id: JSON = "id" <~~ json
else { return nil }
guard let name: String = "label" <~~ container,
link: String = "label" <~~ id
else { return nil }
self.name = name
self.link = link
}
}
Теперь, когда ваши классы готовы, остается позволить Gloss делать свою работу!
Откройте файл playground'a и добавьте следующий код:
import UIKit
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
DataManager.getTopAppsDataFromFileWithSuccess { (data) -> Void in
var json: [String: AnyObject]!
// 1
do {
json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as? [String: AnyObject]
} catch {
print(error)
XCPlaygroundPage.currentPage.finishExecution()
}
// 2
guard let topApps = TopApps(json: json) else {
print("Error initializing object")
XCPlaygroundPage.currentPage.finishExecution()
}
// 3
guard let firstItem = topApps.feed?.entries?.first else {
print("No such item")
XCPlaygroundPage.currentPage.finishExecution()
}
// 4
print(firstItem)
XCPlaygroundPage.currentPage.finishExecution()
}
Серьезно — это — весь код, в котором мы нуждаетесь.
Сохраните и запустите ваш playground; вы снова успешно получили название приложения, но более изящным способом.
App(name: "Game of War - Fire Age", link: "https://itunes.apple.com/us/app/game-of-war-fire-age/id667728512?mt=8&uo=2")
Все это относится к разбору локальных данных. Но как на счет разбора данных с удаленного ресурса?
Настало время сделать этот проект более реальным. В обычном порядке, вы получаете данные c удаленного ресурса, а не с локальных файлов. Можно легко получить рейтинги с App Store с помощью сетевого запроса.
Откройте DataManager.swift и найдете URL для получения лучших приложений:
let TopAppURL = "https://itunes.apple.com/us/rss/topgrossingipadapplications/limit=25/json"
Затем добавьте следующий метод к реализации DataManager:
public class func getTopAppsDataFromItunesWithSuccess(success: ((iTunesData: NSData!) -> Void)) {
//1
loadDataFromURL(NSURL(string: TopAppURL)!, completion:{(data, error) -> Void in
//2
if let data = data {
//3
success(iTunesData: data)
}
})
}
Код выше выглядит довольно знакомым; но вместо получения данных с локального файла, мы использовали NSURLSession, чтобы получить данные с iTunes. Вот что конкретно происходит:
Откройте ваш playground и замените следующий код:
DataManager.getTopAppsDataFromFileWithSuccess { (data) -> Void in
на этот
DataManager.getTopAppsDataFromItunesWithSuccess { (data) -> Void in
Теперь вы получили настоящие данные с iTunes.
Сохраните и запустите ваш playground; вы увидите, что разбор информаций по-прежнему приводит к тому же конечному итогу:
App(name: "Game of War - Fire Age", link: "https://itunes.apple.com/us/app/game-of-war-fire-age/id667728512?mt=8&uo=2")
Значение выше может отличаться, поскольку популярные приложения App Store постоянно меняются.
Часто люди не заинтересованы лишь в ТОП приложениях App Store — они хотят видеть список всех ТОП приложений. Не нужно кодить, чтобы их получить. Достаточно добавить следующий фрагмент кода:
topApps.feed?.entries
Не сложно заметить, что Gloss чудесно выполняет работу парсинга – но что за этим стоит? <~~ это пользовательский оператор (custom operator) для ряда функций Decoder.decode. Gloss имеет встроенную поддержку для декодирования многих типов:
Заметка: Если у вас есть желание больше изучить Custom Operators, посмотрите статью: Operator Overloading in Swift [5]Tutorial
В этой статье мы рассматривали декодируемые модели. Если вам необходимо что-то посложнее, расширьте Decoder и произведите собственную реализацию декодирования.
Конечно, с помощью Gloss можно так же конвертировать объекты в JSON. Если вам это интересно, просмотрите Encodable протокол.
Вот и финальный playground [6].
Вы можете использовать playground как начальный шаг для создания нового приложения; просто замените URL получения данных удаленно с вашим собственным URL, управляйте собственными ключами и индексами вашего нового JSON, и вы создадите новый проект, который буде разбирать что-то, например, результатов футбольных матчей или другие данные полученные с сети.
Разработка Gloss продолжается тут [2] на Github, так что следите за последними обновлениями.
Swift все еще эволюционирует, поэтому вы должны следить за новой документацией от Apple на случай будущих обновлений языка.
Надеюсь вам понравился этот статья о работе с JSON. Если у вас есть вопросы или замечания, их можно обсудить ниже!
Автор: yarmolchuk
Источник [7]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/json/110860
Ссылки в тексте:
[1] JavaScript Object Notation: http://www.json.org/
[2] Gloss: https://github.com/hkellaway/Gloss
[3] Скачайте стартовый playground: http://cdn5.raywenderlich.com/wp-content/uploads/2015/11/TopApps-Starter.zip
[4] Gloss Repo Zip File: https://github.com/hkellaway/Gloss/archive/master.zip
[5] Operator Overloading in Swift : http://www.raywenderlich.com/80818/operator-overloading-in-swift-tutorial
[6] финальный playground: http://cdn2.raywenderlich.com/wp-content/uploads/2015/12/Gloss-final.zip
[7] Источник: https://habrahabr.ru/post/276247/
Нажмите здесь для печати.