Содержание
Цель задания — создать приложение, которое показывает пользователю список наиболее популярных мест на Земле, в которых сделаны фотографии и размещены на сервисе Flickr, а также дает возможность просмотра этих фотографий. Это Задание преследует следующие методические задачи: вы должны научиться работать с Table Views, Scroll Views, Image View и многопоточностью, узнать, как строить универсальные приложения, которые работают на любых как iPhone, так и на iPad (с соответствующим UI на каждом).
Все данные, которые вам необходимы, будут загружаться с Flickr.com c использованием API Flickr. Вам будет предоставлен код для создания URLs запросов к Flickr, которые понадобятся в этом домашнем задании.
Текст Домашнего задания на английском языке доступен на iTunes в пункте “Developing iOS 7 app:Assignment 5″.
На русском языке
Задание выполнялось в Xcode 7 iOS 9. Режимы «Use Auto Layout» и «Use Size classes» в этом Домашнем задании включены.
Код Задания 5 находится на Github. Ниже представлен мой вариант решения Задания 5. У Вас может быть совсем другая логика построения этого приложения.
Это первая часть Задания 5.
Вторая часть Задания 5 находится здесь.
Пункт 1
Загрузите данные с URL, поставляемого методом URLForTopPlaces вспомогательного класса FlickrFetcher, для получения массива наиболее популярных мест, где были сделаны Flickr фотографии за последнее время. Смотри (Подсказки (Hints)) как интерпретировать данные, возвращаемые Flickr.
Создайте новый проект по шаблону Single View Application
Сделайте это приложение универсальным (чтобы оно запускалось на iPhone и iPad)
Добавьте Flickr-API к проекту путем размещения папки Flickr Fetch (полученной с сайта Stanford, но соответствующим образом исправленной).
Получите API key непосредственно на Flickr и установите его в FlickrAPIKey.h.
В классе ViewController, импортируем файл FlickrFetcher.h и создаем свойство NSArray *places для накопления интересующих нас данных с сервиса Flickr.
Массив NSArray *places представляет собой массив словарей, содержащих информацию о местах на Земле, где сделаны фотографии и размещены на Flickr. Будем считывать данные с помощью NSURLSession, поэтому определяем сессию NSURLSession *session, задание на загрузку данных NSURLSessionDownloadTask *task с определенного URL и получаем блок completionHandler:
^(NSURL *location, NSURLResponse *response, NSError *error)
, в котором можем проверять ошибки и вести обработку полученной информации
При обработке следуем подсказкам, находящимся в Задании 5:
Подсказка №3. Данные, возвращаемые с Flickr, представлены в JSON формате. iOS имеет встроенный JSON парсер. Просто создайте NSData, содержащие информацию, возвращаемую с Flickr (используйте метод dataWithContentsOfURL: класса NSData); затем преобразуйте JSON в property list (то есть объекты NSArray и NSDictionary) используя метод класса в NSJSONSerialization с именем JSONObjectWithData:options:error:. Вы можете передать 0 в качестве аргумента для options.
Согласно этой подсказки № 3 получаем код
Подсказка №5. Верхний уровень результатов запроса Flickr — это словарь. Внутри этого словаря находится массив с вашими результатами. Например, для получения массива мест из данных, возвращенных методом URLForTopPlaces (давайте предположим, что вы уже преобразовали Flickr результаты из формата JSON в словарь с именем results) , вы, во-первых, можете использовать NSDictionary *placesResults = results[@”places”] и тогда получаем массив NSArray *places = placesResults[@”place”]. Альтернативно, вы можете сделать это путем вовлечения одного метода:
NSArray *places = [results valueForKeyPath:@”places.place”];
Мы выбрали второй альтернативный вариант применения одного метода
Для того, чтобы получать данные и их обрабатывать, нужно знать URL для запроса наиболее популярных мест на Flickr. Для этого используем подсказку № 4
Подсказка №4. Первая вещь, которую вы, возможно, захотите сделать как только скопируете код FlickrFletcher к себе в приложение (и добавите свой API ключ) — это выберите данные с помощью URLForTopPlaces , затем сделаете парсинг JSON и наконец NSLog() результатов парсинга. Таким образом вы сможете увидеть формат выбранных данных Flickr. Тоже самое можно повторить, когда вы запрашиваете список фотографий для заданного места.
Это соответствует строке кода
[objc]
NSURL *url = [FlickrFetcher URLforTopPlaces];
[/objc]
Печать JSON данных нужно организовывать в main queue, поэтому возвращаемся в блоке в main queue и печатаем содержимое полученных данных на консоли:
Вот результаты печати, и мы можем сделать вывод, что self.places — это массив словарей. Каждый словарь содержит все необходимые данные для определенного местоположения — это описание места (ключ «_content»), это количество фотографий, сделанных в этом месте (ключ «photo_count»), это географические координаты (ключи «latitude» и «longitude»).
[js]
(
{
"_content" = "Bordeaux, Aquitaine, France";
latitude = "44.849";
longitude = "-0.576";
"photo_count" = 92;
"place_id" = VITSM0tUWrqXwo4;
"place_type" = locality;
"place_type_id" = 7;
"place_url" = "/France/Aquitaine/Bordeaux";
timezone = "Europe/Paris";
"woe_name" = Bordeaux;
woeid = 580778;
},
{
"_content" = "Helsinki, Uusimaa, Finland";
latitude = "60.171";
longitude = "24.932";
"photo_count" = 29;
"place_id" = JOvLad9UVL9At9A;
"place_type" = locality;
"place_type_id" = 7;
"place_url" = "/Finland/Uusimaa/Helsinki";
timezone = "Europe/Helsinki";
"woe_name" = Helsinki;
woeid = 565346;
},
{. . . . . . . . . .
[/js]
Пункты 2, 3
2. Создайте UITabBarController пользовательский интерфейс с двумя закладками. Первая закладка показывает UITableView список мест, полученных в обязательном пункте 1, разделенных на секции по странам, а внутри секции по алфавиту. Вторая закладка показывает UITableView список из 20 недавно просмотренных (в вашем приложении) фотографий (в хронологическом порядке с поздним в качестве первого фото и без дупликатов).
3. При появлении популярного места в UITableView в вашем приложении, наиболее детальная часть местоположения (например, имя города) должна быть title ячейки (cell) UITableView, а остальная часть местоположения (например, штат, провинция и т.д.) должна появляться как subtitle ячейки UITableView. Название страны должно быть в заголовке секции.
Для этого на storyboard убираем существующий обычный View Controller и добавляем Tab Bar Controller, убираем два Сontrollers, которые прибыли вместе с Tab Bar Controller. Добавляем два новых Table View Controllers, вставляем их в Navigation Controllers и подсоединяем к Tab Bar Controller. Даем имя закладкам и добавляем иконки для списка мест Top Places и для списка «недавних» фотографий Resents:
Начнем с закладки Top Places. Создадим с помощью меню File -> New -> File -> Cocoa Class пользовательский класс TopPlacesTVC, который наследует от UITableViewController
И назначим этот класс на storyboard Table View Controller, соответствующему закладке Top Places
Кроме того, устанавливаем тип прототипа для ячейки таблицы Subtitle и идентификатор прототипа «Top places«.
Перенесем загрузку данных с Flickr из предыдущего View Controller и добавим методы делегата для Table View. Но сначала разберемся с Моделью. Пусть Модель будет свойство:
@property (nonatomic,strong) NSArray *places;
которое представляет собой массив словарей NSDictionary , отображающих места, где сделаны Flickr фотографии. Этот массив мы получили выше с помощью NSURLSession. Так как наши данные в таблице будут группироваться по странам, то нам понадобится больше, чем просто массив мест places в качестве внутренней структуры данных для UITableViewController. Создадим внешний словарь NSDictionary по странам placesByCountry, в котором ключом будет страна country, а значением — массив мест — словарей, соответствующих этой стране
@property (nonatomic, strong) NSDictionary *placesByCountry;
Мы будем заполнять этот словарь с помощью метода createPlacesByCountryForPlaces всякий раз, как кто-то будет устанавливать нашу Модель, то есть свойство places
. . . . . . . . . . . . . . . . . . .
Теперь у нас есть словарь мест по странам self.placesByCountry и страны self.countries, отсортированные по имени в алфавитном порядке, и мы можем приступить к реализации методов делегата UITableViewController
. . . . . . . . . . . . . . . . .
Для конфигурации ячейки таблицы мы должны получить title и subtitle, которые представляют собой название места и все остальное, связанное с его описанием. Для этого получаем из словаря topPlaceDictionary топового места, соответствующего этой строке таблицы, описание места topPlaceDiscription, которое может выглядеть, например, так
«Mur Mawr, Wales, United Kingdom» или так
«Bollene, Provence-Alpes-Cote d’Azur, France»
Для извлечения элементов названия топового места используем метод componentsJoinedByString для NSString и получаем массив с этими элементами, причем название страны (United Kingdom и France) находится на последнем месте.
Пункт 4
Если пользователь выберет место в UITableView, вы должны опять запросить у Flickr 50 фотографий с этого места и показать их в списке. URL поставляется вспомогательным классом FlickrFetcher и методом класса URLForPhotosInPlace: maxResult: для получения этих фотографий из Flickr.
Перетягиваем на storyboard новый Table View Controllor, не забываем установить идентификатор для прототипа ячейки таблицы «Flickr Photo Cell»
Создаем Show Segue от ячейки первой таблицы (Table View Controller) к этому новому Controller с помощью CTRL-перетягивания.
И не забудем дать идентификатор этому segue:
Создадим новый FlickrPhotos, который наследует от UITableViewControllerCreate и используется для показа списка фотографий с public свойством NSArray *photos, которое представляет собой массив фотографий:
Не забудьте установить пользовательский класс для нашего нового Controller
Каждый раз, когда мы будем устанавливать это свойство, мы будем перегружать данные в таблице:
Реализуем методы DataSource для таблицы со списком фотографий:
Для получения заголовка и подзаголовка в ячейке таблицы фотографий используем дополнительные методы, так как в Задании 5 специально оговаривается как они должны выглядеть. Поэтому временно выполним пункт 5, а затем опять вернемся к пункту 4 и продолжим работу на таблицей со списком фотографий и реализацией перехода на нее из списка популярных мест.
Пункт 5
Любой список фотографий должен показывать заголовок фотографии как title ячейки UITableView, а описание (description) фотографии как subtitle ячейки UITableView. Если у фотографии нет заголовка, используйте описание (description) фотографии как title ячейки. Если у фотографии нет ни заголовка, ни описания, используйте “Unknown” как title ячейки UITableView. Ключи словаря с информацией о Flickr фотографии определены в FlickrFetcher.h.
Создаем два дополнительных метода : один — для title
, другой — для subtitle:
В FlickrFletcher.h имеются #defines для всех интересующих вас ключей к данным из Flickr. У некоторых из них есть точки ”.” и их соответственно можно использовать только с valueForKeyPath:, например, FLICKR_PHOTO_DESCRIPTION.
Полученный класс FlickrPhotos является обобщенным (generic) классом для создания списка Flickr фотографий, причем не имеет значения, откуда взялся этот список фотографий. Для фотографий, полученный для одного из популярных мест мы создадим новый класс PlaceFlickrPhotos, который наследует от FlickrPhotos, и создает список фотографий для топового места. Моделью этого класса, public API, является топовое место place:
При установке этого топового места place мы запрашиваем у Flickr список 50 фотографий с этого места и устанавливаем public API, нашего superclass FlickrPhotos, которым является self.photos:
Нам осталось установить place в методе prepareForSegue для таблицы топовых мест, то есть в классе TopPlacesTVC:
В результате мы получим нужный нам интерфейс
Продолжение выполнения Задания 5 TopPlaces находится здесь. Код Задания 5 находится на Github.