Pull to refresh

Разработка iOS8 приложения на Apple Swift

Reading time6 min
Views62K
Original author: Jameson Quave
Статья является своеобразным продолжением статьи «Знакомьтесь, Swift!» за авторством Helecta, а также вольным переводом статьи Developing iOS Apps Using Swift Tutorial Part 2.



Итак, в первой статье мы написали простое Single View приложение, включающее таблицу с несколькими ячейками.
На этот раз мы немного углубимся и сделаем несколько более амбициозных вещей. Мы будем обращаться к API поиска iTunes, парсить ответ, полученный в JSON и отображать результаты в Table View.
На первый взгляд может показаться, что все это довольно сложно и предстоит много работы, но на самом деле это не так. Все описанное выше является достаточно простым функционалом для iOS приложений и каждый уважающий себя iOS разработчик должен это уметь.

Нам понадобится Single View Application c добавленным Table View. Останавливаться на этом не будем, так как все это достаточно просто описано в первой статье.

Подключение интерфейса


Для начала, нам нужно получить указатель на наш Table View для того чтобы использовать его в коде приложения. Отправляемся в файл ViewController.swift и сразу в инициализации класса (class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {) добавляем следующую строчку:
@IBOutlet var appsTableView : UITableView

Это позволит нам ассоциировать Table View в Storyboard с переменной «appsTableView».
Переходим к Storyboard. Кликаем по View Controller с зажатым control и тянем курсор к Table View, тем самым связывая эти объекты. В появившейся менюшке Outlets выбираем «appsTableView».


Выполнение API запроса


Теперь, после того как мы подключили интерфейс, можно выполнять наши API запросы.
В файле ViewController.swift внутри инициализации класса ViewController создаем функцию searchItunesFor(searchTerm: String).
func searchItunesFor(searchTerm: String) {
    // Для The iTunes API слова в поисковом запросе должны быть разделены при помощи "+", поэтому нам необходимо произвести соответствующие замены.
    var itunesSearchTerm = searchTerm.stringByReplacingOccurrencesOfString(" ", withString: "+", options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil)
    
    // Помимо этого, необходимо удалить все что не URL-friendly
    var escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
    var urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=software"
    var url: NSURL = NSURL(string: urlPath)
    var session = NSURLSession.sharedSession()
    var task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in
        println("Task completed")
        if(error) {
            println(error.localizedDescription)
        }
        var err: NSError?
        var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as NSDictionary
        if(err?) {
            println(error.localizedDescription)
        }
        var results: NSArray = jsonResult["results"] as NSArray
        dispatch_async(dispatch_get_main_queue(), {
            self.tableData = results
            self.appsTableView.reloadData()
            })
        })
    task.resume()
}


Давайте по порядку.
Исправляем наш поисковый запрос, чтобы iTunes API получил текст вида «First+Second+Third+Words» вместо «First%20Second%20…». Для этого мы используем доступный в NSString метод stringByReplacingOccurencesOfString, который заменяет пробелы на "+".
Далее, мы очищаем полученную строку от символов, которые не поддерживаются URL.
Следующие две строчки определяют объект NSURL, который будет использоваться в качестве запроса к API.
Обратим внимание на следующие две строчки:
var session = NSURLSession.sharedSession()
var task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in

Первая берет стандартный объект NSURLSession, который используется для сетевых вызовов.
Вторая создает задание, которое и посылает запрос.
Наконец, строчка task.resume() начинает выполнение запроса.

Подготовка к получению ответа


Мы получили метод, который при вызове выполняет поиск в iTunes. Вставим его в конце метода viewDidLoad в нашем ViewController.
override func viewDidLoad() {
    super.viewDidLoad()
    searchItunesFor("Angry Birds")
}

Теперь, для того чтобы получить ответ, необходимо добавить объект, который будет хранить результаты поиска.
Поэтому, добавим инстанс NSMutableData и массив NSArray, для хранения данных для нашей таблицы (внутри инициализации класса ViewController, например сразу после указателя @IBOutlet var appsTableView: UITableView).
var data: NSMutableData = NSMutableData()
var tableData: NSArray = NSArray()

Теперь, давайте объединим функции, которые NSURLConnection будет отправлять в наш класс. Так как это делегат нашего запроса, любая информация от NSURLConnection будет возвращаться методами протокола, определенными в NSURLConnectionDataDelegate и NSURLConnectionDelegate. Поэтому, в инициализации ViewController укажем также NSURLConnectionDelegate, NSURLConnectionDataDelegate, будет что-то вроде:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, NSURLConnectionDelegate, NSURLConnectionDataDelegate {


Получение ответа


Нам предстоит добавить самый большую часть кода нашего приложения для обработки полученной информации.
func connection(didReceiveResponse: NSURLConnection!, didReceiveResponse response: NSURLResponse!) {
    self.data = NSMutableData()
}

func connection(connection: NSURLConnection!, didReceiveData data: NSData!) {
    self.data.appendData(data)
}

func connectionDidFinishLoading(connection: NSURLConnection!) {
    var err: NSError
    var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options:    NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary

    if jsonResult.count>0 && jsonResult["results"].count>0 {
        var results: NSArray = jsonResult["results"] as NSArray
        self.tableData = results
        self.appsTableView.reloadData()
   }
}

Когда NSURLConnection получает ответ, вызывается метод didReceiveResponse.
Тут мы просто сбрасываем наши данные, если они были, прописывая self.data = NSMutableData() для создания нового объекта.
После установки соединения, мы начинаем получать данные в методе didReceiveData. Здесь передается аргумент data: NSData, где и находится вся интересующая нас информация. Нам нужно сохранить все полученные в ответе части, поэтому мы присоединяем их к объекту self.data, созданному выше.
Наконец, после того как мы в ответе получили всю информацию, вызывается метод connectionDidFinishLoading, где мы уже можем начать использовать результат.
Мы будем использовать класс NSJSONSerialization для преобразования необработанных данных в полезную информацию в виде объектов словаря NSDictionary.
Теперь, когда мы убедились что получен какой-то ответ от iTunes, простой проверки ключа «results» будет достаточно для того чтобы удостовериться что мы получили именно то что ожидали, поэтому мы можем установить объект self.tableData равным results, а также обратиться к методу таблицы appsTableView.reloadData() для обновления ее содержимого.

Обновление интерфейса Table View UI


Для инициализации Table View в первой статье, нам необходимо было определить две функции: одна возвращает количество строк в таблице, вторая создавала ячейки и описывала их содержимое.
Обновим эти функции, в соответствии с новым функционалом.
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
    return tableData.count
}

func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
    let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell")
    var rowData: NSDictionary = self.tableData[indexPath.row] as NSDictionary
    cell.text = rowData["trackName"] as String

    // Обращаемся к ключу artworkUrl60 для получения ссылки на обложку объекта
    var urlString: NSString = rowData["artworkUrl60"] as NSString
    var imgURL: NSURL = NSURL(string: urlString)

    // Скачиваем файл обложки в объект NSData для последующего отображения в ячейке
    var imgData: NSData = NSData(contentsOfURL: imgURL)
    cell.image = UIImage(data: imgData)

    // Получаем цену объекта по ключу formattedPrice и отображаем ее в качестве subtitle
    var formattedPrice: NSString = rowData["formattedPrice"] as NSString
    cell.detailTextLabel.text = formattedPrice

    return cell
}

Функция numberOfRowsInSection теперь просто возвращает количество полученных в ответе объектов.
Функция cellForRowAtIndexPath вместо отображения номера строки теперь отображает название объекта, его обложку и стоимость.

Если все хорошо и у вас получилось запустить приложение, возможно вы заметите некоторые «лаги» во время его работы. Это связано с тем, что мы не предусмотрели несколько вещей, которым уделим внимание в следующей статье.

P.S.: После выхода моего перевода, автор несколько обновил урок, немного оптимизировав код. Перевод я постарался привести в соответствие.
Only registered users can participate in poll. Log in, please.
Переводить ли следующие статьи из этого цикла?
90.29% Да660
9.71% Нет71
731 users voted. 98 users abstained.
Tags:
Hubs:
Total votes 49: ↑41 and ↓8+33
Comments32

Articles