Работаем с форматом JSON в Swift 2.1 Xcode 7

Надеюсь, вы разобрались, что находится в стартовом проекте. Теперь, давайте двигаться дальше!
Разбираем JSON нативным способом Swift
Заметка
Думаю, вы уже знакомы с болью, которая возникает каждый раз, когда вам нужно отпарсить JSON. И, если вы не мазохист :], то вам лучше пропустить эту секцию и сразу перейти к SwiftyJSON.
Сначала, мы отпарсим JSON оригинальным способом Swift, то есть мы не будем использовать никаких внешних библиотек. Это поможет нам оценить пользу библиотеки SwiftyJSON.
Давайте отпарсим предоставленный нам файл JSON, для того, чтобы получить имя первого в списке лучших приложений US AppStore.
Откройте ViewController.swift и добавьте следующий код в конец метода viewDidLoad():
DataManager.getTopAppsDataFromFileWithSuccess { (data) -> Void in // Get the number 1 app using optional binding and NSJSONSerialization //1 do { let parsedObject: AnyObject? = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments) //2 if let topApps = parsedObject as? NSDictionary { if let feed = topApps["feed"] as? NSDictionary { if let apps = feed["entry"] as? NSArray { if let firstApp = apps[0] as? NSDictionary { if let imname = firstApp["im:name"] as? NSDictionary { if let appName = imname["label"] as? NSString { //3 print("Optional Binding: \(appName)") } } } } } } } catch let error as NSError? { print("error: \(error?.localizedDescription)") } }Прокручиваете глазами этот каскадный список закрывающихся скобок? :] Вот что у нас тут происходит:
- Сначала вы десериализуете (преобразуете из последовательного формата в параллельный), используя NSJSONSerialization.
- Затем, вам нужно проверить каждое значение сабскрипта в объекте JSON, чтобы убедиться, что они не nil.
- После того, как вы уверены, что они не nil, вы ищите следующий объект.
- После того, как вы прошли весь путь через все сабскрипты, вы получаете отображение значения appName.
Если какой-либо элемент в JSON будет неожиданным, то вы получите полный беспорядок и имя приложения никогда не появится у вас на экране.
- Последний шаг — просто выводим значения appName в дебаггере.
Запустите ваше приложение: вы должны увидеть в вашей консоли дебаггера вот что:
Optional Binding: Clash of Clans
Да, “Clash of Clans” является приложением #1 в файле JSON.
Мы написали достаточно много кода, для того, чтобы получить всего лишь название приложения. Самое время посмотреть как будет работать SwiftyJSON.
Интрегрирование SwiftyJSON в ваш проект
Эту библиотеку очень просто интегрировать.
Перейдите на страницу SwiftyJSON github. Затем, перетащите SwiftyJSON\SwiftyJSON.swift в наигацию вашего проекта Xcode. Убедитесь, что у вас стоит галочка на Copy items if needed и что у вас выбрано TopApps, затем, нажмите Finish
Вот и все! Вы только что интегрировали библиотеку в ваш проект, и теперь вы можете парсить JSON без головной боли опциональной привязки!
Парсим JSON через SwiftyJSON
SwiftyJSON позволяет вам пропустить все ваши проверки значения на nil, то есть, теперь вы можете получить имя приложения #1, используя всего одно выражение if.
Замените метод viewDidLoad() следующим:
override func viewDidLoad() { super.viewDidLoad() DataManager.getTopAppsDataFromFileWithSuccess { (data) -> Void in // Get #1 app name using SwiftyJSON let json = JSON(data: data) if let appName = json["feed"]["entry"][0]["im:name"]["label"].string { print("SwiftyJSON: \(appName)") } } }И это весь код, который вам понадобится!
Сначала, вы создаете константу JSON, через метод int типаJSON() и ваш объект данных. Затем, SwiftyJSON конвертирует эти данные в объект JSON, используя NSJSONSerialization.
Бонус использования библиотеки в том, что она берет на себя все опциональные проверки, которые ранее вы делали вручную. Все что вам нужно, это знать ключи и индексы, которые вы хотите получить, а остальное вы можете доверить SwiftyJSON.
Итак, мы хотим получить строковое значение, по этому передаем .stringValue в конец процесса парсинга. Если необходимо получить массив, то передаем .arrayValue. Остальные возвращаемые типы используют аналогичную конструкцию.
Запустите ваше приложение, и вы увидите, как получено имя приложения, только, теперь вы использовали значительно меньше кода:
SwiftyJSON: Clash of Clans
Библиотека берет на себя парсинг локальных данных, но как она работает с удаленным источником данных?
Получение удаленного JSON
Самое время сделать наш проект более реальным. Обычно, мы будем получать удаленные данные и не с локального файла. Вы можете просто взять рейтинг приложений AppStore, используя онлайн запрос.
Идем в DataManager.swift и добавляем следующий метод:
class func getTopAppsDataFromItunesWithSuccess(success: ((iTunesData: NSData!) -> Void)) { //1 loadDataFromURL(NSURL(string: TopAppURL)!, completion:{(data, error) -> Void in //2 if let urlData = data { //3 success(iTunesData: urlData) } }) }Этот код выглядит достаточно знакомым, но вместо получения локального файла, вы используете NSURLSession, для извлечения данных с iTunes. Вот что происходит в деталях:
Сначала вы вызываете метод loadDataFromURL(), который принимает URL и замыкание (closure), которое передает объект NSData. Следующим шагом вы проверяете существование значения, используя опциональную привязку. Наконец, вы передаете данные в замыкание success, как мы делали ранее. Откройте ViewController.swift и добавьте следующие строки в конец метода viewDidLoad():
// Get the #1 app name from iTunes and SwiftyJSON DataManager.getTopAppsDataFromItunesWithSuccess { (iTunesData) -> Void in let json = JSON(data: iTunesData) if let appName = json["feed"]["entry"][0]["im:name"]["label"].string { print("NSURLSession: \(appName)") } // More soon... }Код выше практически такой же, как тот, который вы писали в первой секции, но теперь вы получаете данные из iTunes.
Запустите ваше приложение и вы увидите, что мы все еще получаем то же заключение, по поводу имени приложения #1:
SwiftyJSON: Clash of Clans NSURLSession: Clash of Clans
На самом деле, значения сверху могут отличаться, так как лучшие приложения AppStore тоже меняются.
Обычно, люди интересуются не только лучшими приложениями в AppStore, но они так же хотят видеть все лучшие приложения. Это значит, что вам нужно получить массив рейтинга топовых приложений.
Разбираем JSON для заполнения массивов
Добавьте следующий код в ViewController.swift, сразу после комментария “More soon”:
//1 if let appArray = json["feed"]["entry"].array { //2 var apps = [AppModel]() //3 for appDict in appArray { let appName: String? = appDict["im:name"]["label"].string let appURL: String? = appDict["im:image"][0]["label"].string let app = AppModel(name: appName, appStoreURL: appURL) apps.append(app) } //4 print(apps) }Код, который приведен выше, перебирает все приложения в ответе JSON и создает модели объекта AppModel:
- Сначала вы получаете список приложений с SwiftyJSON
- Следующим шагом вы создаете изменяемый массив для хранения объектов, которые будут созданы.
- Затем, вы перебираете все элементы и создаете AppModel из данных JSON.
- И последнее, вы выводите на экран список новых объектов в консоли дебаггера.
Запустите приложение. Вы увидите предыдущие три результата попытки разбора JSON, а затем, список 25 лучших приложений в iTunes store:

В реальных приложениях вы можете использовать код, написанный выше, и можете реализовать UICollectionView и UITableView для отображения этих результатов.
Вот и все что нужно, для использования JSON в Swift. Остальная часть туториала опциональна, так как она посвящена работе SwiftyJSON непосредственно под “капотом”.
Заглядываем под капот SwiftyJSON
Вы конечно уже можете оценить, как хорошо работает SwiftyJSON, но давайте заглянем ему под капот.
Когда вы вызываете JSON(), вы передаете экземпляр опционального NSData или даже AnyObject. JSONValue() является инициализатором для перечисления (enum) в SwiftyJSON:
public enum JSON { case ScalarNumber(NSNumber) case ScalarString(String) case Sequence(Array) case Mapping(Dictionary) case Null(NSError?) // ... }Помните, что для того чтобы получить разные значения из возвращенного JSON, вам нужны разные ключи и индексы. Ниже приведен код, который позволяет вам получить имя приложения #1 в AppStore:
json["feed"]["entry"][0]["im:name"]["label"]
Оно работает через сабскрипт языка Swift:
extension JSON { // ... subscript(key: String) -> JSON { get { switch self { case .Mapping(let dictionary) where dictionary[key] != nil: return dictionary[key]! default: return .Null(NSError(domain: SwiftyJSONErrorDomain, code: 0, userInfo: nil)) } } } }Обратите внимание, что результатом оператора сабскрипта является другой объект JSON. Зависит от вас, какой тип вы хотите вернуть из этого JSON. В нашем случае, мы хотим вернуть имя приложения, то есть тип Sting, так что вы просто добавляете .stringValue в конец объекта JSON.
extension JSON { var string: String? { get { switch self { case .ScalarString(let string): return string case .ScalarNumber(let number): return number.string default: return nil } } } // ... }Метод string() один из множества способов, которые названы в честь типа, который они возвращают из объекта JSON. Каждая функция возвращает опциональную тезку типа.
var string: String? var number: NSNumber? var URL: NSURL? var char: Int8? var unsignedChar: UInt8? var short: Int16? var unsignedShort: UInt16? var long: Int? var unsignedLong: UInt? var longLong: Int64? var unsignedLongLong: UInt64? var float: Float? var double: Double? var integer: Int? var unsignedInteger: Int?
Обратите внимание, что все значения являются опциональными, так что мы защищены от значения равного nil. Вот так SwiftyJSON обрабатывает опциональную привязку.
Но, мы пока что еще не затронули обработку ошибки в SwiftyJSON. Вот как можно обработать неправильное условие в SwiftyJSON:
let json = JSON(dataFromNetworking)["some_key"]["some_wrong_key"]["wrong_name"] if json{ // обработка удачна } else { print(json) //> JSON Keypath Error: Incorrect Keypath "some_wrong_key/wrong_name" //вам всегда сообщается, где ваш ключ стал некорректным switch json{ case .JInvalid(let error): // NSError содержит детальный отчет об ошибке } }Мы очень рекомендуем посмотреть как работает SwiftyJSON, так как эта библиотека демонстрирует качественную комбинацию полезных техник Swift, для получения отличного результата.
Конечный проект вы можете скачать здесь.
Что дальше?
Дальше, вы можете продолжить изучать наши туториалы по мере их появления, а также, параллельно читать перевод официальной книги по языку программирования Swift. И, для более подробного изучения языка, вы можете пройти наши курсы!
Урок подготовил: Иван Акулов
Источник урока: http://www.raywenderlich.com/82706/working-with-json-in-swift-tutorial
Originally published at swiftbook.ru on November 24, 2015.