Вандад Нахавандипур - iOS. Приемы программирования
10.6. Обнаружение щипка
Постановка задачи
Необходимо предоставить пользователю возможность выполнять движения щипка.
Решение
Создайте экземпляр класса UIPinchGestureRecognizer и добавьте его к вашему целевому виду, воспользовавшись методом экземпляра addGestureRecognizer:, относящимся к классу UIView:
— (void)viewDidLoad {
[super viewDidLoad];
CGRect labelRect = CGRectMake(0.0f, /* X */
0.0f, /* Y */
200.0f, /* Ширина */
200.0f); /* Высота */
self.myBlackLabel = [[UILabel alloc] initWithFrame: labelRect];
self.myBlackLabel.center = self.view.center;
self.myBlackLabel.backgroundColor = [UIColor blackColor];
/* Без этой строки распознаватель щипков работать не будет. */
self.myBlackLabel.userInteractionEnabled = YES;
[self.view addSubview: self.myBlackLabel];
/* Создаем распознаватель щипков. */
self.pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc]
initWithTarget: self
action:@selector(handlePinches:)];
/* Добавляем этот распознаватель жестов к виду. */
[self.myBlackLabel
addGestureRecognizer: self.pinchGestureRecognizer];
}
Контроллер вида определяется так:
#import «ViewController.h»
@interface ViewController ()
@property (nonatomic, strong)
UIPinchGestureRecognizer *pinchGestureRecognizer;
@property (nonatomic, strong) UILabel *myBlackLabel;
@property (nonatomic, unsafe_unretained) CGFloat currentScale;
@end
Обсуждение
Щипки позволяют пользователю легко масштабировать (увеличивать и уменьшать) элементы графического интерфейса. Например, браузер Safari в iOS дает возможность щипком на веб-странице увеличивать ее содержимое. Щипок работает в двух направлениях: увеличение и уменьшение масштаба. Это непрерывный жест, который на сенсорном экране всегда выполняется двумя пальцами.
Данный распознаватель жестов может пребывать в следующих состояниях:
• UIGestureRecognizerStateBegan;
• UIGestureRecognizerStateChanged;
• UIGestureRecognizerStateEnded.
Как только щипок распознан, вызывается действующий метод целевого объекта (и будет последовательно вызываться до тех пор, пока щипок не окончится). В действующем методе вы получаете доступ к двум очень важным методам распознавателя щипков: scale и velocity. scale — это коэффициент, на который нужно изменить размер элемента графического интерфейса по осям X и Y, чтобы отразить таким образом размер пользовательского жеста. velocity — это скорость щипка, измеряемая в пикселах в секунду. Скорость имеет отрицательное значение, если пальцы движутся навстречу друг другу, и положительное — если они перемещаются в разные стороны.
Значение свойства scale можно передать функции CGAffineTransformMakeScale из фреймворка Core Graphics, чтобы получить аффинное преобразование. Такое преобразование применимо к свойству transform любого экземпляра класса UIView, оно позволяет изменять преобразование этого элемента. Мы воспользуемся этой функцией следующим образом:
— (void) handlePinches:(UIPinchGestureRecognizer*)paramSender{
if (paramSender.state == UIGestureRecognizerStateEnded){
self.currentScale = paramSender.scale;
} else if (paramSender.state == UIGestureRecognizerStateBegan &&
self.currentScale!= 0.0f){
paramSender.scale = self.currentScale;
}
if (paramSender.scale!= NAN &&
paramSender.scale!= 0.0){
paramSender.view.transform =
CGAffineTransformMakeScale(paramSender.scale,
paramSender.scale);
}
}
Поскольку свойство scale распознавателя жестов сбрасывается всякий раз, когда регистрируется новый щипок, мы сохраняем последнее значение этого свойства в общем свойстве экземпляра (Instance Property) контроллера вида, называемом currentScale. В следующий раз, когда будет распознан новый жест, мы отсчитываем коэффициент масштабирования от последнего зафиксированного значения, что и продемонстрировано в коде.
Глава 11. Сетевые функции, JSON, XML и Twitter
11.0. Введение
Стоит подключить приложение iOS к Интернету — и оно становится гораздо интереснее. Например, представьте себе приложение, которое предлагает пользователям великолепные фоновые картинки для Рабочего стола. Пользователь может выбрать вариант из большого списка изображений и присвоить любой из этих рисунков в качестве фонового операционной системе iOS. А теперь вообразим себе приложение, которое делает то же самое, но обновляет ассортимент имеющихся изображений каждый день, неделю или месяц. Пользователь после какого-то перерыва возвращается к работе с программой и — опа! Масса новых фоновых изображений динамически загружается в приложение. В этом и есть изюминка работы с веб-службами и Интернетом. Реализовать такие функции не составляет труда, если обладать базовыми знаниями о работе в Сети, применении JSON, XML и Twitter. Ну, еще от разработчика приложения требуется известная креативность.
iOS SDK позволяет подключаться к Интернету, получать и отсылать данные. Это делается с помощью класса NSURLConnection. Сериализация и десериализация JSON выполняется в классе NSJSONSerialization. Синтаксический разбор XML производится с помощью NSXMLParser, а соединение с Twitter обеспечивается во фреймворке Twitter.
В SDK iOS 7 появились новые классы, работать с которыми мы научимся в этой главе. В частности, поговорим о классе NSURLSession, который управляет соединяемостью веб-сервисов и решает эту задачу более основательно, чем класс NSURLConnection. О соединяемости мы также поговорим далее в этой главе.
11.1. Асинхронная загрузка с применением NSURLConnection
Постановка задачи
Необходимо асинхронно загрузить файл с имеющегося URL.
Решение
Используйте класс NSURLConnection с асинхронным запросом.
Обсуждение
Класс NSURLConnection можно использовать двумя способами — асинхронным и синхронным. При асинхронном соединении создается новый поток, и процесс загрузки выполняется в этом новом потоке. Синхронное соединение блокирует вызывающий поток, а содержимое загружается прямо в ходе обмена данными.
Многие разработчики полагают, что при синхронном соединении блокируется главный поток, но это неверно. Синхронное соединение всегда блокирует тот поток, в котором оно было инициировано. Если вы запускаете синхронное соединение из главного потока — да, главный поток будет заблокирован. Но синхронное соединение, запущенное из другого потока, будет напоминать асинхронное именно в том отношении, что оно никак не повлияет на главный поток. На самом деле единственное различие между синхронным и асинхронным соединениями заключается в том, что для асинхронного соединения среда времени исполнения создает отдельный поток, а для синхронного — нет.
Чтобы создать асинхронное соединение, необходимо следующее.
1. Иметь URL или экземпляр NSString.
2. Преобразовать строку в экземпляр NSURL.
3. Поместить URL в URL-запросе типа NSURLRequest, а если мы имеем дело с изменяемыми URL — в экземпляр NSMutableURLRequest.
4. Создать экземпляр NSURLConnection и передать ему URL-запрос.
Можно создать асинхронное соединение по URL с помощью метода класса sendAsynchronousRequest: queue: completionHandler:, относящегося к классу NSURLConnection. Этот метод имеет следующие параметры:
• sendAsynchronousRequest — запрос типа NSURLRequest, рассмотренный ранее;
• queue — операционная очередь. При желании можно просто выделить и инициализировать новую операционную очередь и передать ее этому методу;
• completionHandler — блоковый объект, выполняемый, когда асинхронное соединение завершает работу, успешно или неуспешно. Этот блоковый объект должен принимать три параметра:
• объект типа NSURLResponse, в котором заключается ответ, полученный нами от сервера, — при наличии такого ответа;
• данные типа NSData при их наличии. Это будут данные, собранные в ходе соединения по указанному URL;
• ошибка типа NSError в случае ее возникновения.
Метод sendAsynchronousRequest: queue: completionHandler: не вызывается в главном потоке. Поэтому, если вам потребуется решить задачу, связанную с пользовательским интерфейсом, убедитесь, что вернулись к главному потоку.
Итак, довольно теории, перейдем к примерам. В данном примере попытаемся собрать HTML-контент с домашней страницы Apple, а потом выведем эту информацию в строковом формате в окне консоли:
NSString *urlAsString = @"http://www.apple.com";
NSURL *url = [NSURL URLWithString: urlAsString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL: url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection
sendAsynchronousRequest: urlRequest