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

Содержание

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

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

iOS 9 Задания


Для выполнения Задания 4 необходим материал  Лекции 8 и Лекции 9. Исходное приложение Smashtag L9 находится на сайте Стэнфорда для Xcode 7 и Swift 2.2. Если вы установили Xcode 8, то для Swift 2.3 код находится на Github, а для Swift 3 — также на Github.

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

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

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

Если вы установили Xcode 8, то для Swift 2.3 код находится на Github, а для Swift 3 — также на Github.

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

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

В подсказке № 25 Задания 4 предлагается идея создания глобального “хранилища” для недавних поисковых терминов в NSUserDefaults. Мы создаем структуру RecentSearches, в которой использована идея работы с массивом, сохраняемым в NSUserDefaultsчерез вычисляемую переменную. В нашем случае public API для класса  RecentSearches будет static массив строк searches: [String]  недавнего поиска, который хранится в NSUserDefaults

Screen Shot 2016-07-19 at 10.43.24 AM
.   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .
Мы должны дополнить этот класс двумя  static  методами: один из них добавляет строку поиска в массив searches, удовлетворяя требованиям уникальности и  временной актуальности добавляемой строки, другой должен уметь удалять элемент массива с определенным индексом.

Screen Shot 2016-07-19 at 10.38.29 AM

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

Screen Shot 2016-07-19 at 10.50.34 AM

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

Screen Shot 2016-07-19 at 10.53.37 AM

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

Screen Shot 2016-07-19 at 11.10.49 AM

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

Screen Shot 2016-07-19 at 11.13.20 AM

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

Screen Shot 2016-07-19 at 11.20.33 AM

С учетом добавления UITabBarController, storyboard будет выглядеть как представлено на рисунках. Оказалось, что storyboard трудно уместить на одном рисунке. Поэтому она показана на двух рисунках с небольшим смещение влево.

Screen Shot 2016-07-19 at 11.32.52 AM

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

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

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

Screen Shot 2016-07-19 at 11.38.55 AM

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

Screen Shot 2015-07-10 at 1.13.47 PM

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

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

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

Код для Обязательных пунктов 1- 10 можно найти на Github для Xcode 7 и Swift 2.2. Если вы установили Xcode 8, то для Swift 2.3 код находится на Github, а для Swift 3 — также на Github.

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

Задание 4. CS193P Spring 2016. Smashtag Mentions (клиент Twitter). Решение — обязательные пункты 8 — 10.: 5 комментариев

  1. Здравствуйте!
    При использовании вычисляемой переменной выходит, что каждый раз при обращении к recentSearches в функции tableView(_, _) -> UITableViewCell контроллера RecentTableViewController мы обращаемся к NSUserDefaults.standardUserDefaults()? Правильно ли это? Не проще ли использовать не вычисляемую переменную, а обычную, просто инициализируемую в том же ViewDidLoad() или ViewWillAppear()? Заранее благодарю.

    • Я не очень понимаю, о чем вы говорите.
      Ведь в структуре RecentSearches определена константа, которая вычисляется один раз (static):
      private static let defaults = NSUserDefaults.standardUserDefaults()?
      Если вы хотите такую константу получить в RecentTableViewControlle, то задавайте ее непосредственно там:
      let defaults = NSUserDefaults.standardUserDefaults()?
      А причем здесь ViewDidLoad() или ViewWillAppear()?

      • К сожалению, я ошибочно полагал, что метод synchronize() вызывается каждый раз при обращении к объекту класса NSUserDefaults. Прошу прощения.

Обсуждение закрыто.