Задание 4. CS193P Winter 2017. Smashtag Mentions (клиент Twitter). Решение — обязательные пункты 8 — 10.

Содержание

Текст Домашнего Задания 4 на английском языке доступен на  iTunes в пункте “Programming: Project 4: Smashtag Mentions″На русском языке вы можете скачать здесь:

Задание 4 iOS 10.pdf

iOS 10 Задания


В Задании 4 вы должны усовершенствовать приложение Smashtag, которое мы создали на Лекции 9, чтобы обеспечить быстрый доступ к хэштэгам hashtags, URLs urls, изображениям images и пользователям users, упомянутым в твите. Основными идеями в этом Задании являются многопоточность, работа с таблицей Table View, глубокое знание Navigation Controller, множественные MVC типа Tab Bar Controller и работа с изображениями с помощью Scroll View.

Основой для решения Задания 4 является демонстрационный пример «Smashtag L9«, код которого доступен как на  iTunes название “Lecture 9 Demo Code: Smashtag«, так и на Github.

Начало решения Задания 4 находится в посте Задание 4. CS193P Winter 2017. Smashtag Mentions (клиент Twitter). Решение — обязательные пункты 1- 7.

В данном посте представлено решение Обязательных пунктов 8 — 10 Задания 4.

Код для Обязательных пунктов 1- 7 находится на Github .
Код для Обязательных пунктов 1- 10 находится на Github.

Пункты 8 обязательный

Сохраняйте недавние 100 поисков в Twitter, которые пользователь выполнил в вашем приложении. Добавьте UITabBarController к вашему приложению с одной закладкой для поиска (то есть ваш главный UI) и второй закладкой, показывающей недавние поисковые термины, используемые для поиска в вашей таблице (они должны быть уникальны и первыми должны быть самые новые). Когда пользователь кликает на поисковом термине во второй закладке, “переезжайте” (segue) (оставаясь в той же самой закладке) куда-то, чтобы показать самые свежие твиты, соответствующие этому поисковому термину. Запомните эти недавно выполненные поисковые термины в постоянном хранилище, так чтобы ваше приложение не забывало их в случае повторного старта приложения.

В подсказке № 25 Задания 4 предлагается идея создания глобального “хранилища” для недавних поисковых терминов в UserDefaults.

Возможно, хорошая идея — иметь глобальное “хранилище” для недавних поисковых терминов, так как вам все равно нужно запоминать их в хранилище UserDefaults. Почему бы не сделать этим хранилищем UserDefaults? Вы можете создать маленький класс или структуру для хранения и извлечения данных из хранилища UserDefaults, которую можно использовать всюду в вашем приложении.

Мы создаем структуру RecentSearches, в которой использована идея работы с массивом, сохраняемым в UserDefaultsчерез вычисляемую переменную. В нашем случае public API для класса  RecentSearches будет static массив поисковых строк searches: [String], который хранится в UserDefaults:


.   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .
Мы должны дополнить этот класс двумя  static  методами: один из них добавляет строку поиска в массив searches, удовлетворяя требованиям уникальности и  временной актуальности добавляемой строки, другой должен уметь удалять элемент массива searches с определенным индексом index :

Добавлять строки поиска в хранилище RecentSearches.searches мы будем при задании поисковой строки searchText в классе TweetTableViewController :

А доставать из хранилища RecentSearches.searches мы будем в методе «жизненного цикла» viewDidLoad в классе TweetTableViewController при условии, что searchText не был установлен ранее в процессе подготовки к «переезду» на этот MVC:

Для второй закладки UITabBarController нужно построить MVC, показывающий недавние поисковые термины, используемые для поиска в вашей таблице твитов. Эти недавние поисковые термины находятся в хранилище RecentSearches.searches и мы можем их использовать для отображения в таблице. Перетягиваем Table View Controller из палитры объектов, создаем новый subclass UITableViewController, который назовем  RecentTableViewController, и не забываем выставить этот класс на  storyboard для вновь созданного Table View Controller. Эту операцию мы делали много раз, и я не буду на ней подробно останавливаться. Для таблицы недавних поисковых терминов public API — это  массив поисковых строк  recentSearches:

Как только нам становится известен массив  recentSearches отображаемых данных в таблице, задача отображения сводится к реализации методов делегата dataSource, которые мы ниже представим. Но у этой таблице есть «изюминка». Дело в том, что этот массив нам никто не дает, а он хранится и постоянно обновляется в хранилище UserDefaults. Чтобы извлечь оттуда самые свежие данные, мы должны «перезагружать» таблицу при каждом новом появлении ее на экране. Это лучше всего делать в методе viewWillApear «жизненного цикла» View Controller, который содержит обращение к методу reloadData(), и заставит заработать методы  делегата dataSource,опирается на Модель recentsSearches:

Когда пользователь кликает на поисковом термине во второй закладке, нас просят “переезжать” (segue) (оставаясь в той же самой закладке) на Table View Controller, чтобы показать самые свежие твиты, соответствующие этому поисковому термину. Это будет тот же самый Table View Controller, на который мы «переезжали» с таблицы меншенов в Обязательном пункте 5. Код для метода prepare (for seque:, sender:) тоже стандартный:

Вы можете провести отладку экранного фрагмента Recents без  UITabBarController. Для этого вставляем экранный фрагмент Recents в Navigation Controller и перебрасываете на него маленькую стрелочку старта приложения.

С учетом добавления UITabBarController, storyboard будет выглядеть как представлено на рисунке ниже:

 

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

Пункт 9 обязательный

Сетевые запросы никогда не должны блокировать main thread в вашем приложении.

К счастью, мы уже позаботились об этом. Метод fetchTweets класса TwitterRequest во фреймворке Twitter выполняет свой handler за пределами main thread. В ImageViewController использовалась многопоточная обработка, которая подробно объяснялась на Лекции 8. Загрузка изображение профайла  tweetProfileImageView  в пользовательском классе TweetTableViewCell для отображения твита в ячейке таблицы также происходит за пределами main queue на некоторой глобальной очереди . Для обновления изображения на UI мы возвращаемся обратно на main queue :

Отметим важность строки, выделенной синим цветом. Она позволяет предотвратить обработку данных, пришедших из сети и потерявших актуальность. Дело в том, что cells таблицы UITableView создаются только для видимых ячеек, и затем они используются повторно по мере того, как данные приходят на экран и уходят с экрана. Так что при скроллинге нашей таблицы твитов, данные о миниатюре могут подгрузиться, а сама ячейка уже «ушла» с экрана и нет смысла размещать ее на UI.
Эта функция используется при обновлении пользовательского интерфейса ячейки

Пункт 10 обязательный

Ваше приложение должно работать правильно как в портретном, так и в ландшафтном режимах на любом iPhone (это приложение только для iPhone).

Мы везде правильно использовали механизм Autolayout, поэтому выполнение этого пункта обеспечивается автоматически:

Код для Обязательных пунктов 1- 10 можно найти на Github.

Продолжение находится в посте Задание 4. CS193P Winter 2017. Smashtag Mentions (клиент Twitter). Решение — дополнительные пункты 1-5.