Это продолжение решение Задания 4. Начало находится в посте Задание 4. Решение — обязательные пункты 1 — 4. Необходимо освоение Лекции 7, Лекции 9, Лекции 10, и Лекции 11. Если вы выполните хотя бы все обязательные пункты Задания 4, то работа с TableView, segue и представлением изображения с «подкачкой» данных в параллельной не main queue очереди (concurrent queue) не будет для вас проблемой никогда.
Текст Задания 4 на английском языке доступен на iTunes в пункте “Developing iOS 8 app: Programming: Project 4″. Текст Домашнего задания на русском языке доступен на
В этом посте подробно описывается выполнение обязательных пунктов 5-10.
Код для Swift 1.2 находится на Github. Код для Swift 2.0 находится на Github.
Пункты 5 и 6 обязательные
5. Если пользователь выбирает какой-то hashtag или user в таблице “mentions”, созданной в вышеприведенном Обязательном пункте № 2, то вы должны куда-то “переехать” (segue), чтобы показать результаты поиска в Twitter этого hashtag или user. Это должен быть поиск именно hashtags или users, а не просто строки с именем hashtag или user (например, поиск “#stanford”, а не “stanford”). View Controller, куда вы “переедите” (segue), должен работать точно также, как ваш главный View Controller, показывающий твиты (TweetTableViewController).
6. Если пользователь кликает на “меншене” url в вашем вновь созданном View Controller, вы должны открыть этот url в Safari (смотри раздел “Подсказки”, приведенный ниже, и узнай как это сделать).
Используем подсказку №15, которая говорит
15. Когда вы кликаете на user или hashtag в вашем “mentions” MVC, вы можете “переехать” (segue) на TableViewController “список твитов” с помощью либо нормального “Show” segue либо с помощью “Unwind” segue. Вам решать, какой из них приведет к созданию лучшего пользовательского интерфейса.
Мы выбираем вариант «переезда» с помощью нормального “Show” segue от прототипа ячейки Keyword Cell к копии TweetTableViewController и задаем идентификатор segue «From Keyword». Скопированный Controller имеет заголовок Tweets.
В классе MentionsTableViewController выполняем метод prepareForSegue
Однако в случае с url, который также подпадает под прототипа ячейки Keyword Cell, мы должны открыть этот url в Safari, то есть предотвратить срабатывание segue. Это можно сделать с помощью метода
Скопированный Controller Tweets должен показывать меншены. В коде класса TweetTableViewController это предусмотрено с помощью segue с идентификатором «Show Mentions«. Поэтому давайте создадим такой segue. Достаточно придерживаться имени, указанного в коде, и у вас все заработает.
Пункты 7 обязательный
Если пользователь кликнет на изображении (image) в вашем вновь созданном View Controller, “переезжайте” на новый MVC, который позволит пользователю прокручивать (scroll) изображение и изменять его масштаб. Когда изображение впервые появляется в MVC, оно должно быть показано в увеличенном масштабе (но со своим нормальным соотношением сторон (aspect ratio)) и так, чтобы занять как можно больше экранного пространства без “белых зазоров” вокруг изображения.
Используя подсказки №21 и 22, копируем ImageViewController из проекта «Cassini» на нашу storyboard и создаем нормальный “Show” segue от прототипа ячейки Image Cell к только что скопированному ImageViewController. Задаем идентификатор segue «Show Image«.
В классе MentionsTableViewController выполняем метод prepareForSegue
Согласно подказкам № 21 и 22 нам следует добавить в ImageViewController автоматическую “подгонку” (autozooming-to-fit) изображения под полный размер экрана путем изменения масштаба. Что это значит? Давайте посмотрим на рисунок.
На вышеприведенном рисунке мы «подгоняем» вертикальный размер изображения под вертикальный размер экрана, и если при этом сохраняется соотношение сторон, то масштаб изображения увеличивается. Как подсчитать масштаб? Рассчитываем две величины:
- масштаб по вертикали Mв = H экрана /H изобр. ≈ 1.2
- масштаб по горизонтали Mг = W экрана /W изобр.≈ 0.6
Берем большее значение 1.2 делаем «подгонку» по вертикали. Это означает, что по вертикали скроллинга не будут, скроллить можно по горизонтали, если вы хотите посмотреть все изображение.
Теперь посмотрим другую ситуацию, которая может появиться при ландшафтном режиме просмотра.
Опять рассчитываем две величины:
масштаб по вертикали Mв = H экрана /H изобр. ≈ 0.6
масштаб по горизонтали Mг = W экрана /W изобр.≈ 1.1
Берем большее значение 1.1 делаем «подгонку» по горизонтали.Это означает, что по горизонтали скроллинга не будут, скроллить можно по вертикали, если вы хотите посмотреть все изображение.
Как видно из рисунков, желательно иметь «подгонку» не только по масштабу, но и по центру изображения. Все это обеспечивается методом zoomScaleToFit и переменной autoZoomed
Переменная autoZoomed устанавливается в true при установке image и тут же запускается режим автоматической «подгонки»
Удовлетворяя подсказке № 22 Задания 4, запускаем режим автоматической «подгонки» при изменении геометрии прибора, то есть в методе viewDidLayoutSubviews «жизненного цикла» View Controller.
Переменная autoZoomed будет сбрасываться, как только пользователь сам начнет выполнять zooming, то есть в методе scrollViewWillBeginZooming делегата ScrollView
Запускаем приложение, находим твит с image и кликаем на этом image.
Все прекрасно работает.
Пункты 8 обязательный
Сохраняйте недавние 100 поисков в Twitter, которые пользователь выполнил в вашем приложении. Добавьте UITabBarController к вашему приложению с одной закладкой для поиска (то есть ваш главный UI) и второй закладкой, показывающей недавние поисковые термины, используемые для поиска в вашей таблице (они должны быть уникальны и первыми должны быть самые новые). Когда пользователь кликает на поисковом термине во второй закладке, “переезжайте” (segue) (оставаясь в той же самой закладке) куда-то, чтобы показать самые свежие твиты, соответствующие этому поисковому термину. Запомните эти недавно выполненные поиски в постоянном хранилище NSUserDefaults так, чтобы ваше приложение не забывало их в случае повторного старта приложения.
В подсказке № 23 Задания 4 предлагается идея создания глобального “хранилища” для недавних поисковых терминов в NSUserDefaults. Мы создаем класс RecentSearches в котором использована идея работы с массивом, сохраняемым в NSUserDefaults, через вычисляемую переменную. Реализацию этой идеи профессор продемонстрировал в Лекции 7, рассматривая демонстрационный пример «Psychologist Popover«. В нашем случае public API для класса RecentSearches будет массив строк searches: [String] недавнего поиска, который хранится в NSUserDefaults.
Мы должны дополнить этот класс двумя public методами: один из них добавляет строку поиска в массив searches, удовлетворяя требованиям уникальности и временной актуальности добавляемой строки, другой должен уметь удалять элемент массива с определенным индексом.
Добавлять строки поиска мы будем, когда задается строка поиска в классе TweetTableViewController и мы приступаем к ее обработке.
Теперь мы можем использовать массив searches для отображения недавних поисковых терминов. Для этого перетягиваем Table View Controller из палитры объектов, создаем новый subclass UITableViewController, который назовем RecentTableViewController, и не забываем выставить этот класс на storyboard для вновь созданного Table View Controller. Эту операцию мы делали много раз, и я не буду на ней подробно останавливаться. Для таблицы недавних поисковых терминов public API является экземпляр recents созданного нами класса RecentSearches, который будет поставлять нам недавние поисковые термины виде массива строк recents.searches.
Как только нам становится известен массив отображаемых данных в таблице, задача отображения сводится к реализации методов DataSource, которые мы ниже представим. Но у этой таблице есть «изюминка». Дело в том, что этот массив нам никто не дает, а он постоянно обновляется в хранилище NSUserDefaults. Чтобы извлечь оттуда самые свежие данные, мы должны «перезагружать» таблицу при каждом новом появлении ее на экране. Это лучше всего делать в методе viewWillApear «жизненного цикла» View Controller.
Реализации методов DataSource опирается на массив recents.searches.
Когда пользователь кликает на поисковом термине во второй закладке, нас просят “переезжать” (segue) (оставаясь в той же самой закладке) на Table View Controller, чтобы показать самые свежие твиты, соответствующие этому поисковому термину. Это будет тот же самый Table View Controller, на который мы «переезжали» с таблицы меншенов в обязательном пункте 5. Код для метода prepareForSeque тоже стандартный
С учетом добавления UITabBarController, storyboard будет выглядеть как представлено на рисунках. Оказалось, что storyboard трудно уместить на одном рисунке. Поэтому она показана на двух рисунках с небольшим смещение влево.
Код для Swift 1.2 находится на Github. Код для Swift 2.0 находится на Github.
Пункт 9 обязательный
Сетевые запросы никогда не должны блокировать mainthread в вашем приложении.
К счастью, мы уже позаботились об этом. Метод fetchTweets класса TwitterRequest выполняет свой handler за пределами main thread. В ImageViewController использовалась многопотоковая обработка, которая подробно объяснялась на Лекции 9. Однако загрузка миниатюры tweetProfileImageView в пользовательском классе TweetTableViewCell для отображения твита в ячейке таблицы все еще происходит с блокировкой main queue. Добавим специальную функцию для загрузки этого изображения в параллельной очереди, как мы поступили при загрузке изображения в классе ImageViewController
Отметим важность строки, выделенной синим цветом. Он позволяет предотвратить обработку данных, пришедших из сети и потерявших актуальность. Дело в том, что cells таблицы UITableView создаются только для видимых ячеек, и затем они используются повторно по мере того, как данные приходят на экран и уходят с экрана. Так что при скроллинге нашей таблицы твитов, данные о миниатюре могут подгрузиться, а сама ячейка уже «ушла» с экрана и нет смысла размещать ее на UI.
Эта функция используется при обновлении пользовательского интерфейса ячейки
Код для Swift 1.2 находится на Github. Код для Swift 2.0 находится на Github.
Пункт 10 обязательный
Ваше приложение должно работать правильно как в портретном, так и в ландшафтном режимах на любом iPhone (это приложение только для iPhone).
Мы везде правильно использовали механизм Autolayout, поэтому выполнение этого пункта обеспечивается автоматически.
Приложение становится всё интереснее >>>
А на какой версии Swift вы программируете?
Swift4 🙂
Swift 4, но iOS 10, Да?
11.1 😉
А как вы используете фреймворк Twitter, разработанный профессором? Ведь iOS 11 больше не поддерживает использование Twitter через встроенный Social фреймворк.
Пришлось разобраться и использовать TwitterKit. Мигрировал на новый Swift, кое-что изменил и всё заработало.
У меня тоже есть вариант с TwitterKit https://bestkora.com/IosDeveloper/obnovlenie-demonstratsionnyh-primerov-i-reshenij-zadanij-kursa-ios-10-swift-3-do-swift-4-i-ios-11/ и в папке iOS11 на Github.
Но меня там не все устраивает. Хотелось бы посмотреть, как вы решили проблему. В частности, удалось ли сохранить отдельный фреймворк Twitter,созданный профессором? Мне пришлось сделать все в одном проекте без workspace.
Можете дать ссылку на ваше решение?
ПОжалуйста! 🙂
https://github.com/VictorShurapov/Smashtag-Assignment-4-iOS-11