Когда несколько лет назад Лорен Бричтер представила идею «тянуть, чтобы освежить» в Tweetie 2, разработчики не сразу приняли эту гениальную и интуитивно понятную концепцию. Несмотря на то, что теперь Twitter владеет патентом на концепцию «pull to refresh», это не помешало Apple представить класс UIRefreshControl в iOS 6. Этот новый подкласс UIControl позволяет UIControl добавлять элемент управления «pull to refresh» в любую таблицу. просмотр контроллера в iOS 6.
Короткая и сладкая
Ссылка на класс UIRefreshControl коротка, намекая на то, как легко начать работу с этим добавлением фреймворка UIKit. Класс UIRefreshControl непосредственно происходит от UIControl , что означает, что настройка экземпляра UIRefreshControl мало чем отличается от создания и настройки любого другого элемента управления UIKit. После создания экземпляра класса UIRefreshControl вы назначаете его новому свойству refreshControl объекта контроллера табличного представления ( UITableViewController или его подкласса). Контроллер табличного представления заботится о правильном позиционировании и отображении элемента управления обновлением. Как и с любым другим подклассом UIControl , вы присоединяете пару целевого действия к определенному событию, UIControlEventValueChanged в случае UIRefreshControl .
Это не будет учебник по Mobiletuts + без примера, иллюстрирующего, как использовать класс UIRefreshControl в проекте. В оставшейся части этого руководства я покажу вам, как заполнить табличное представление списком твитов, извлеченных из API поиска Twitter. Запрос отправляется в API поиска Twitter, когда пользователь тянет табличное представление dow: pull-to-refresh.
Шаг 1: Настройка проекта
Приложение, которое мы собираемся создать, запрашивает в Twitter Search API твиты о разработке для iOS . Запрос отправляется в API поиска Twitter, когда пользователь перемещает представление таблицы вниз, открывая элемент управления обновлением. Мы будем использовать фантастическую библиотеку AFNetworking для отправки нашего запроса в API поиска Twitter. AFNetworking также поможет нам асинхронно загружать и отображать изображения профиля.
Создайте новый проект в XCode, выбрав пустой шаблон приложения из списка шаблонов ( рисунок 1 ). Назовите свое приложение Pull-to-Refresh , введите идентификатор компании, установите iPhone для семейства устройств и установите флажок Использовать автоматический подсчет ссылок . Остальные флажки могут быть оставлены непроверенными для этого проекта (рисунок 2). Сообщите Xcode, где вы хотите сохранить проект, и нажмите кнопку « Создать» .


Шаг 2. Добавление библиотеки AFNetworking
Установка AFNetworking с использованием Cocoapods очень проста . Однако в этом руководстве я покажу вам, как вручную добавить библиотеку AFNetworking в проект Xcode, чтобы убедиться, что мы все на одной странице. В любом случае это не так сложно.
Загрузите последний стабильный выпуск библиотеки со страницы проекта GitHub , распакуйте архив и перетащите папку с именем AFNetworking в ваш проект Xcode. Убедитесь, что установлен флажок Копировать элементы в папку целевой группы (если необходимо), и дважды проверьте, что библиотека добавлена в цель Pull-to-Refresh (рисунок 3).

Библиотека AFNetworking опирается на две платформы, с которыми новый проект XCode по умолчанию не связан, (1) Конфигурация системы и (2) Платформы мобильных базовых сервисов. Выберите свой проект в Навигаторе проектов , выберите цель « Потянуть для обновления» из списка целей и откройте вкладку « Фазы сборки » вверху. Разверните блок « Связать двоичные файлы с библиотеками» и добавьте обе платформы, нажав кнопку «плюс» (рисунок 4).

Чтобы закончить, добавьте оператор импорта для обеих платформ, а также AFNetworking в предварительно скомпилированный заголовочный файл проектов, как показано в фрагменте ниже. Это облегчит работу с AFNetworking, поскольку нам не нужно добавлять оператор импорта для каждого класса, в котором мы хотим использовать библиотеку.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
//
// Prefix header for all source files of the ‘Pull to Refresh’ target in the ‘Pull to Refresh’ project
//
#import <Availability.h>
#ifndef __IPHONE_3_0
#warning «This project uses features only available in iOS SDK 3.0 and later.»
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <MobileCoreServices/MobileCoreServices.h>
#import <SystemConfiguration/SystemConfiguration.h>
#import «AFNetworking.h»
#endif
|
Шаг 3: Создание контроллера табличного представления
UIRefreshControl предназначен для работы в сочетании с объектом контроллера табличного представления. Создайте новый подкласс UITableViewController ( File> New> File … ), выбрав шаблон класса Objective C из списка шаблонов ( рисунок 5 ). Дайте новому классу имя MTTweetsViewController и дважды проверьте, что это подкласс UITableViewController . Скажите Xcode, что он не должен создавать nib-файл для нового класса контроллера, сняв флажок с меткой XIB для пользовательского интерфейса (рисунок 6). Укажите местоположение для сохранения нового класса и нажмите кнопку « Создать» .


Шаг 4: Добавление элемента управления обновлением
Прежде чем мы сможем добавить элемент управления обновлением в контроллер табличного представления, нам нужно создать экземпляр нового класса MTTweetsViewController . Обновите application:didFinishLaunchingWithOptions: метод в MTAppDelegate.m, как показано ниже. Реализация не должна содержать сюрпризов. Мы инициализируем экземпляр класса MTTweetsViewController и устанавливаем его как корневой контроллер окна приложения. Не забудьте добавить оператор импорта в верхней части MTAppDelegate.m, чтобы импортировать файл MTTweetsViewController класса MTTweetsViewController .
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
— (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Initialize Tweet View Controller
MTTweetsViewController *vc = [[MTTweetsViewController alloc] initWithStyle:UITableViewStylePlain];
// Initialize Window
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Configure Window
[self.window setBackgroundColor:[UIColor whiteColor]];
[self.window setRootViewController:vc];
// Make Key and Visible
[self.window makeKeyAndVisible];
return YES;
}
|
|
1
|
#import «MTTweetsViewController.h»
|
Если вы запустите приложение в iPhone Simulator, вы должны увидеть пустое табличное представление. Элемент управления обновлением добавляется в метод viewDidLoad контроллера представления твитов. Как я упоминал ранее, добавить элемент управления обновлением очень просто. Взгляните на реализацию метода viewDidLoad показанную ниже. Мы инициализируем элемент управления обновлением и добавляем цель и действие для события UIControlEventValueChanged элемента управления обновлением. Наконец, элемент управления обновлением назначается refreshControl контроллера табличного представления. Конечно, свойство refreshControl также является новым для iOS 6.
|
01
02
03
04
05
06
07
08
09
10
11
12
|
— (void)viewDidLoad {
[super viewDidLoad];
// Initialize Refresh Control
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
// Configure Refresh Control
[refreshControl addTarget:self action:@selector(refresh:) forControlEvents:UIControlEventValueChanged];
// Configure View Controller
[self setRefreshControl:refreshControl];
}
|
Прежде чем мы снова соберем и запустим проект, нам нужно реализовать действие refresh: в файле реализации контроллера представления. Чтобы убедиться, что все настроено правильно, мы просто записываем сообщение на консоль. Создайте и запустите проект, чтобы увидеть элемент управления обновлением в действии.
|
1
2
3
4
|
— (void)refresh:(id)sender
{
NSLog(@»Refreshing»);
}
|
Вы заметите, что элемент управления обновлением не исчезает после того, как он был показан контроллером табличного представления. Это то, что вам придется делать самостоятельно. Идея элемента управления обновлением в некоторой степени аналогична представлению индикатора активности UIActivityIndicatorView ( UIActivityIndicatorView ), то есть вы несете ответственность за его отображение и скрытие. Сокрыть элемент управления обновлением так же просто, как отправить ему сообщение endRefreshing . Обновите действие refresh: как показано ниже и снова запустите приложение в iPhone Simulator.
|
1
2
3
4
5
6
|
— (void)refresh:(id)sender {
NSLog(@»Refreshing»);
// End Refreshing
[(UIRefreshControl *)sender endRefreshing];
}
|
Элемент управления обновлением немедленно исчезает после освобождения представления таблицы. Конечно, это делает управление обновлением совершенно бесполезным. Что мы сделаем, это отправим запрос в API поиска в Твиттере и скроем элемент управления обновлением, когда мы получим ответ (или когда истечет время ожидания запроса). AFNetworking делает это очень просто.
Шаг 5: Запрос API поиска в Твиттере
Мы будем хранить твиты, которые мы получаем от API поиска Twitter, в виде массива. Добавьте частное свойство с именем твиты в класс MTTweetsViewController как показано ниже.
|
1
2
3
4
5
6
7
|
#import «MTTweetsViewController.h»
@interface MTTweetsViewController ()
@property (strong, nonatomic) NSArray *tweets;
@end
|
Затем обновите numberOfSectionsInTableView: tableView:numberOfRowsInSection: и tableView:cellForRowAtIndexPath: методы, как показано ниже. Если вы раньше работали с табличными представлениями, это не должно быть слишком сложным для понимания.
|
1
2
3
|
— (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.tweets ?
}
|
|
1
2
3
|
— (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.tweets count] ?
}
|
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
— (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @»Cell Identifier»;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// Fetch Tweet
NSDictionary *tweet = [self.tweets objectAtIndex:[indexPath row]];
// Configure Cell
[cell.textLabel setText:[tweet objectForKey:@»text»]];
[cell.detailTextLabel setText:[tweet objectForKey:@»from_user»]];
// Download Profile Image Asynchronously
NSURL *url = [NSURL URLWithString:[tweet objectForKey:@»profile_image_url»]];
[cell.imageView setImageWithURL:url placeholderImage:[UIImage imageNamed:@»placeholder»]];
return cell;
}
|
В tableView:cellForRowAtIndexPath: мы создаем новую ячейку (или удаляем из нее многократно используемую ячейку) и заполняем ее содержимым твита. Чтобы обеспечить плавную прокрутку табличного представления, мы загружаем изображение профиля пользователя асинхронно. Это очень легко сделать с помощью AFNetworking, поскольку оно дает нам setImageWithURL:placeholderImage: Что это делает, так это настройка представления изображения ячейки с помощью предоставленного изображения заполнителя при запросе изображения профиля пользователя в фоновом режиме. Чтобы сделать это, добавьте placeholder.png и placeholder@2x.png в ваш проект Xcode. Вы можете найти оба файла в исходных файлах этого урока.
Мы отправляем наш запрос в API поиска Twitter в действии refresh: . Посмотрите на обновленную реализацию ниже. Я не буду вдаваться в подробности того, как AFJSONRequestOperation класс AFJSONRequestOperation в этом учебном пособии, но я хочу объяснить, как работает поток запроса. После указания URL-адреса запроса ( NSURL ) и инициализации запроса URL-адреса ( NSURLRequest ) мы создаем операцию запроса JSON, передавая (1) запрос URL-адреса, (2) блок успеха и (3) блок сбоя JSONRequestOperationWithRequest:success:failure: Блок succes выполняется, если запрос был успешным, и дает нам ответ на запрос как экземпляр NSDictionary . Мы извлекаем массив запрашиваемых твитов, обновляем свойство tweets , перезагружаем табличное представление, чтобы показать твиты, и скрываем элемент управления обновлением, отправляя ему сообщение endRefreshing.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
— (void)refresh:(id)sender {
// Create URL
NSURL *url = [NSURL URLWithString:@»http://search.twitter.com/search.json?q=ios%20development&rpp=100&include_entities=true&result_type=mixed/»];
// Initialize URL Request
NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:url];
// JSON Request Operation
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:urlRequest success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSArray *results = [(NSDictionary *)JSON objectForKey:@»results»];
if ([results count]) {
self.tweets = results;
// Reload Table View
[self.tableView reloadData];
// End Refreshing
[(UIRefreshControl *)sender endRefreshing];
}
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
// End Refreshing
[(UIRefreshControl *)sender endRefreshing];
}];
// Start Operation
[operation start];
}
|
Если запрос не выполняется, мы скрываем только элемент управления обновлением. Конечно, было бы лучше проинформировать пользователя о том, что запрос не выполнен, но это будет сделано для нашего примера. Мы отправляем запрос, начиная операцию запроса JSON в конце действия refresh: .
Создайте и запустите проект еще раз, чтобы увидеть пример приложения в действии. Если изображения профиля не отображаются правильно, проверьте еще раз, что вы добавили изображения-заполнители, которые я упоминал ранее, в ваш проект.

Вывод
Есть много библиотек, которые пытаются имитировать оригинальную функциональность «тянуть, чтобы обновить», но приятно видеть, что Apple наконец-то приняла эту изящную концепцию и включила ее в инфраструктуру UIKit. Как вы могли заметить, в iOS 6 Apple уже UIRefreshControl класс UIRefreshControl для использования в некоторых своих собственных приложениях, таких как приложение Podcasts.