Статьи

Быстрый доступ к персонажам Marvel

В детстве я постоянно поглощал Marvel Comics. В последнее время с появлением регулярных фильмов Marvel вновь появился интерес к вселенной Marvel. Marvel любезно выпустил  API,  который разрешил доступ ко всем вещам от их персонажей до комиксов и событий. В этой статье будет показано, как получить доступ к Marvel API из приложения iOS, написанного на Swift.

Первое, что вам нужно сделать, это зарегистрировать аккаунт разработчика на  http://developer.marvel.com/ . Это даст вам открытые / закрытые ключи и доступ к их документации. Ключи необходимы для доступа к API.

Моей отправной точкой было ванильное iOS-приложение «Single View» Я использовал  cocoapods  для настройки зависимостей. Для этого приложения я решил использовать  SwiftHttp  для HTTP-коммуникаций и  JSONJoy-Swift,  чтобы отобразить ответ JSON обратно в структуру Swift.

Мой подфайл выглядит так.

source 'https://github.com/CocoaPods/Specs.git'  
platform :ios, '8.1'

pod 'SwiftHTTP', :git => "https://github.com/daltoniam/SwiftHTTP.git", :tag => "0.9.1"  
pod 'JSONJoy-Swift', :git => "https://github.com/daltoniam/JSONJoy-Swift.git", :tag => "0.9.1" 

После настройки я добавил простой вид iOS с UIImageView и кнопкой загрузки.

Что будет делать приложение, нажав кнопку загрузки, мы получим доступ к API, загрузим подробную информацию о  «Человеке-муравье»  и установим его эскиз в виде изображения.

1. Мы получим доступ к информации о «Человеке-муравье» через API персонажа комиксов. Чтобы получить его данные, мы отправим HTTP-запрос GET на http://gateway.marvel.com:80/v1/public/characters/  с несколькими параметрами:

  • его имя
  • API-ключ (открытый ключ)
  • ts (временная метка или значение, которое изменяется за запрос)
  • хеш (md5 хэш ts + открытый ключ + закрытый ключ)

Более подробную информацию об API можно найти  здесь

2. Определите IBAction для кнопки загрузки. В рамках действия мы создадим HTTP-запрос и начнем загрузку.

@IBAction func download(sender: AnyObject) {

    }

Добавьте оператор импорта в начало файла ViewController.

import SwiftHTTP  
import JSONJoy  

Для создания HTTP-запроса нам нужно создать HTTPTask. Наша первая итерация метода будет выглядеть следующим образом.

    @IBAction func download(sender: AnyObject) {
        let name = "Ant-Man"
        let url = "http://gateway.marvel.com:80/v1/public/characters"
        var request = HTTPTask()
        let publicKey = "YOUR PUBLIC KEY"
        let ts = NSDate().timeIntervalSince1970.description

        request.GET(url, parameters: ["nameStartsWith": name, "apikey": publicKey, "ts" : ts], success: { (response: HTTPResponse) -> Void in
            println("got a response: \(response.responseObject)")
        },{(error: NSError, response: HTTPResponse?) -> Void in
            println("got an error: \(error)")
        })
      }

Заполните ваш открытый ключ открытым ключом из вашей учетной записи разработчика. Мы используем параметр nameStartsWith для извлечения Ant-Man

3. Запрос не будет работать, если мы не хешируем закрытый ключ и не передадим его в качестве параметра. Для этого потребуется применить хеш MD5 к временной метке, объединенной с открытым ключом и закрытым ключом. Для выполнения хеширования MD5 в Swift я использовал эту  суть,  которая расширяет класс String для добавления метода MD5.

Итак , создайте файл с именем «Swift-MD5.swift» и добавить содержимое  сути  там. Вам нужно будет добавить файл заголовка моста в importCommonCrypto / CommonCrypto.h, который необходим для хеширования MD5.

Мы можем создать хеш для нашего запроса сейчас.

        let publicKey = "YOUR PUBLIC KEY"
        let privateKey = "YOUR PRIVARE KEY"
        let ts = NSDate().timeIntervalSince1970.description
        let hash = "\(ts)\(privateKey)\(publicKey)".md5()

4. Собирая все вместе, наша функция загрузки будет выглядеть так:

    @IBAction func download(sender: AnyObject) {
        let name = "Ant-Man"
        let url = "http://gateway.marvel.com:80/v1/public/characters"
        var request = HTTPTask()
        let publicKey = "YOUR PUBLIC KEY"
        let privateKey = "YOUR PRIVARE KEY"
        let ts = NSDate().timeIntervalSince1970.description
        let hash = "\(ts)\(privateKey)\(publicKey)".md5()

        request.GET(url, parameters: ["nameStartsWith": name, "apikey": publicKey, "ts" : ts], success: { (response: HTTPResponse) -> Void in
            println("got a response: \(response.responseObject)")
        },{(error: NSError, response: HTTPResponse?) -> Void in
            println("got an error: \(error)")
        })
      }

Запуск приложения и нажатие кнопки загрузки инициирует запрос. Это приведет к выводу текста, как показано ниже в консоли.

got a response: Optional({  
    attributionHTML = "<a href=\"http://marvel.com\">Data provided by Marvel. \U00a9 2015 MARVEL</a>";
    attributionText = "Data provided by Marvel. \U00a9 2015 MARVEL";
    code = 200;
    copyright = "\U00a9 2015 MARVEL";
    data =     {
        count = 2;
        limit = 20;
        offset = 0;
        results =     
        ...
            etag = b38bb16e6d445c247e1edb3b5decde4f3caa1b2d;
    status = Ok;

5. Чтобы сделать что-то значимое с выводом, мы проанализируем его и преобразуем в структуру, чтобы мы могли использовать данные. Давайте определим класс структуры.

Поэтому создайте файл с именем Character.swift. Добавьте поля, которые мы будем анализировать из ответа. Файл должен напоминать содержимое ниже:

import Foundation  
import JSONJoy

struct Character : JSONJoy {  
    var status: String?
    var code: Int?
    var thumbnail: String?

    init() {
    }

    init(_ decoder: JSONDecoder) {
        status = decoder["status"].string
        code = decoder["code"].integer
        if let arr = decoder["data"]["results"].array {
            let path = arr[0]["thumbnail"]["path"].string
            let fileExtension = arr[0]["thumbnail"]["extension"].string
            thumbnail = "\(path!).\(fileExtension!)"
        }
    }
}

Мы используем  JSONJoy-Swift  для анализа ответа. Код принимает ответ в соответствии с документацией и присваивает его полям в структуре.

Теперь в нашем методе загрузки нам нужно проанализировать ответ в структуре символов.

@IBAction func download(sender: AnyObject) {
        let name = "Ant-Man"
        let url = "http://gateway.marvel.com:80/v1/public/characters"
        var request = HTTPTask()
        request.responseSerializer = JSONResponseSerializer()
        let publicKey = "YOUR PUBLIC KEY"
        let privateKey = "YOUR PRIVATE KEY"
        let ts = NSDate().timeIntervalSince1970.description
        let hash = "\(ts)\(privateKey)\(publicKey)".md5()

        request.GET(url, parameters: ["nameStartsWith": name, "apikey": publicKey, "ts" : ts, "hash": hash], success: { (response: HTTPResponse) -> Void in
            if (response.responseObject != nil) {
                let character = Character(JSONDecoder(response.responseObject!))
            }
        },{(error: NSError, response: HTTPResponse?) -> Void in
            println("got an error: \(error)")
        })
    }

Мы добавили responseSerializer, чтобы он был JSONResponseSerializer. И мы преобразовали ответ в структуру символов.

6. Последняя часть головоломки — загрузить миниатюру и назначить ее для UIImageView. Для этого мы будем использовать SwiftHTTP и скачать изображение, используя это. Мы добавим метод, который принимает структуру символов, загружает миниатюру и назначает ее для UIImageView. Я не буду вдаваться в подробности этого метода, так как в действительности речь идет о том, как использовать SwiftHTTP, а не о том, как использовать API Marvel, о котором пойдет речь в этой статье.

func downloadCharacter(character: Character) {  
        var request = HTTPTask()
        let downloadTask = request.download(character.thumbnail!, parameters: nil, progress: {(complete: Double) in
            println("percent complete: \(complete)")
            }, success: {(response: HTTPResponse) in
                println("download finished!")
                if response.responseObject != nil {
                    let data = NSData(contentsOfURL: response.responseObject! as NSURL)
                    dispatch_async(dispatch_get_main_queue()) {
                        self.imageView.image = UIImage(data: data!)
                    }
                }

            } ,failure: {(error: NSError, response: HTTPResponse?) in
                println("failure")
        })
    }

Обратите внимание, что назначение imageView происходит в основном потоке. Это правильный способ обновления любого объекта просмотра.

7. Так что, если мы соберем все вместе сейчас. Мы можем вызвать функцию downloadCharacter из нашей функции загрузки.

@IBAction func download(sender: AnyObject) {
        let name = "Ant-Man"
        let url = "http://gateway.marvel.com:80/v1/public/characters"
        var request = HTTPTask()
        request.responseSerializer = JSONResponseSerializer()
        let publicKey = "YOUR PUBLIC KEY"
        let privateKey = "YOUR PRIVATE KEY"
        let ts = NSDate().timeIntervalSince1970.description
        let hash = "\(ts)\(privateKey)\(publicKey)".md5()

        request.GET(url, parameters: ["nameStartsWith": name, "apikey": publicKey, "ts" : ts, "hash": hash], success: { (response: HTTPResponse) -> Void in
            if (response.responseObject != nil) {
                let character = Character(JSONDecoder(response.responseObject!))
                self.downloadCharacter(character)
            }
        },{(error: NSError, response: HTTPResponse?) -> Void in
            println("got an error: \(error)")
        })
    }

Мы должны иметь возможность запустить наше приложение, нажать кнопку «Загрузить» и увидеть Ant-Man во всей его красе.

Ну это все. Надеюсь, вы видели достаточно, чтобы начать использовать API Marvel в приложении Swift. Удачи в создании собственного приложения, использующего замечательную вселенную Marvel.

Вот несколько ссылок: