Используем Regular expression в Xcode

Некоторые считают, что в Xcode отсутствует поиск с помощью регулярных выражений(regexp), но это не так!
Например, нужно заменить во всех файлах проекта такой код:

[backgroundView setBackgroundColor:[[UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"background1.png"]]];

на такой:

[backgroundView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"background1.png"]]];

Для того что бы в коде сделать поиск с помощью RegExp нужно в режиме поиска нажать на иконку лупы и выбрать Show Find Options:

В графе Style выбрать Regular Expression и ввести необходимые регулярные выражения для поиска и замены.
В данном случае, для поиска:
\[\[UIColor alloc\] initWithPatternImage:(.+?)\]\];
Для замены:
\[UIColor colorWithPatternImage:\1\]\];

Regular expression find and replace

Вот и все! Данный поиск работает как для всего проекта глобально, так и по коду.

Интеграция Vkontakte API в IOS приложение

В этой небольшой статье я хотел бы поделиться способами интеграции Вконтакте API в проект IOS.
По этой теме сейчас в интернете мало информации и возможно мои советы кому-то помогут. Я покажу как можно не только получить данные пользователя, но и разместить на стене фотографию, текст и ссылку, а так же случай с вводом капчи.

Проект с примером лежит на github.com – https://github.com/maiorov/VKAPI

Документацию по методам API ВКонтакте можно почитать тут

Статьи из других источников на эту тему:
1. appleinsider.ru
2. imaladec.net

Итак, несколько этапов в работе с VK API:
1. Авторизация пользователя через UIWebView и получение accessToken’a и идентификатора пользователя.
2. Использование VK API, запросы и получение данных:

3. Logout пользователя

Часть 0. Регистрация приложения
Как выяснилось, не самая тривиальная часть операции, из-за того, что ВКонтакте несколько форм создания mobile-приложений! Для правильной регистрации нужно воспользоваться ссылкой http://vkontakte.ru/editapp?act=create&site=1, выбрать тип приложения Standalone-приложение. Параметры в настройках можно не указывать. Нужно лишь скопировать ID приложения. В моем примере для этого параметра используется appID.

Часть 1. Авторизация.
Для работы по протоколу Oauth 2.0 с VK API нам понадобится accessToken и user_id. Мы можем получить его отправив запрос на сервер VK через веб-браузер UIWebView, в ответ на запрос сервер ВКонтакте выдаст форму авторизации пользователя, после прохождения авторизации мы получим accessToken, user_id (id пользователя, который ввел свои данные), expires_in (время действия токена). Для этого в новом проекте создадим view-controller, назовем его например vkLoginViewController. Это будет контроллер отвечающий за авторизацию пользователя, при успешной авторизации, он сохраняет полученные параметры в NSUserDefaults и вызывает метод делегата authComplete.

Подробный код вы можете посмотреть в примере. Здесь я разберу только основные моменты.

Добавив в контроллер UIWebView *vkWebView, мы делаем запрос:

    NSString *authLink = [NSString stringWithFormat:@"http://api.vk.com/oauth/authorize?client_id=%@&scope=wall,photos&redirect_uri=http://api.vk.com/blank.html&display=touch&response_type=token", appID];
    NSURL *url = [NSURL URLWithString:authLink];
    
    [vkWebView loadRequest:[NSURLRequest requestWithURL:url]];

Тут client_id это id вашего приложения, scope=wall,photos – это права доступа, которые приложение запрашивает у пользователя (wall размещение на стене, photos нужно чтобы размещать изображения на стене)

В функции webViewDidFinishLoad получаем ответ от сервера ВКонтакте:

-(void)webViewDidFinishLoad:(UIWebView *)webView {
    // Если есть токен сохраняем его
    if ([vkWebView.request.URL.absoluteString rangeOfString:@"access_token"].location != NSNotFound) {
        NSString *accessToken = [self stringBetweenString:@"access_token=" 
                                                andString:@"&" 
                                              innerString:[[[webView request] URL] absoluteString]];
        
        // Получаем id пользователя, пригодится нам позднее
        NSArray *userAr = [[[[webView request] URL] absoluteString] componentsSeparatedByString:@"&user_id="];
        NSString *user_id = [userAr lastObject];
        NSLog(@"User id: %@", user_id);
        if(user_id){
            [[NSUserDefaults standardUserDefaults] setObject:user_id forKey:@"VKAccessUserId"];
        }
        
        if(accessToken){
            [[NSUserDefaults standardUserDefaults] setObject:accessToken forKey:@"VKAccessToken"];
            // Сохраняем дату получения токена. Параметр expires_in=86400 в ответе ВКонтакта, говорит сколько будет действовать токен.
            // В данном случае, это для примера, мы можем проверять позднее истек ли токен или нет
            [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:@"VKAccessTokenDate"];
            [[NSUserDefaults standardUserDefaults] synchronize];
        }
        
        NSLog(@"vkWebView response: %@",[[[webView request] URL] absoluteString]);
        [(ViewController *)delegate authComplete];
        [self dismissModalViewControllerAnimated:YES];
    } else if ([vkWebView.request.URL.absoluteString rangeOfString:@"error"].location != NSNotFound) {
        NSLog(@"Error: %@", vkWebView.request.URL.absoluteString);
        [self dismissModalViewControllerAnimated:YES];
    }
    
}

После этого, мы получили все необходимое: accessToken, user_id. И передаем делегату, что авторизация успешно пройдена, больше нам этот контроллер не нужен и мы его убираем:

[(ViewController *)delegate authComplete];
[self dismissModalViewControllerAnimated:YES];

Часть 2. Запросы к API.
Теперь начинается самое интересное! В примере в контроллере ViewController я подготовил несколько функций, по которым вы сможете понять как работать с API.

2.1 Отправка текста на стену пользователя
Возьмем, для примера, функцию отправки текста на стену:

- (void) sendText {
    NSString *user_id = [[NSUserDefaults standardUserDefaults] objectForKey:@"VKAccessUserId"];
    NSString *accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:@"VKAccessToken"];
    
    NSString *text = @"Работать с ВКонтакте API легко!";
    
    // Создаем запрос на размещение текста на стене
    NSString *sendTextMessage = [NSString stringWithFormat:@"https://api.vk.com/method/wall.post?owner_id=%@&access_token=%@&message=%@", user_id, accessToken, [self URLEncodedString:text]];
    NSLog(@"sendTextMessage: %@", sendTextMessage);
    
    // Если запрос более сложный мы можем работать дальше с полученным ответом
    NSDictionary *result = [self sendRequest:sendTextMessage withCaptcha:NO];
    // Если есть описание ошибки в ответе
    NSString *errorMsg = [[result objectForKey:@"error"] objectForKey:@"error_msg"];
    if(errorMsg) {
        [self sendFailedWithError:errorMsg];
    } else {
        [self sendSuccessWithMessage:@"Текст размещен на стене!"];
    }
}

Для простоты примера, я храню данные в NSUserDefaults. Авторизация пройдена, значит у нас есть все необходимое чтобы составить запрос. Используя метод wall.post, передаем id пользователя (owner_id) и токен (access_token), сообщение text для параметра message мы предварительно прогоняем через функцию URLEncodedString:

// Функция преобразования текста в подходящий для передачи формат
- (NSString *)URLEncodedString:(NSString *)str
{
    NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
                                                                           (CFStringRef)str,
                                                                           NULL,
																		   CFSTR("!*'();:@&=+$,/?%#[]"),
                                                                           kCFStringEncodingUTF8);
    [result autorelease];
	return result;
}

После того, как мы подготовили запрос, нужно отправить его на сервер с помощью функции:

[self sendRequest:sendTextAndLinkMessage withCaptcha:NO];

Как вы можете заметить, фунцкция принимает параметр withCaptcha:(BOOL) это понадобится нам в случае, если сервер затребует ввод капчи у пользователя для подтверждения действий. Так как пока что капча не требуется, мы передаем NO.

Собственно, сама функция отправки запроса:

- (NSDictionary *) sendRequest:(NSString *)reqURl withCaptcha:(BOOL)captcha {
    // Если это запрос после ввода капчи, то добавляем в запрос параметры captcha_sid и captcha_key
    if(captcha == YES){
        NSString *captcha_sid = [[NSUserDefaults standardUserDefaults] objectForKey:@"captcha_sid"];
        NSString *captcha_user = [[NSUserDefaults standardUserDefaults] objectForKey:@"captcha_user"];
        // Добавляем к запросу данные для капчи. Не забываем, что введенный пользователем текст нужно обработать.
        reqURl = [reqURl stringByAppendingFormat:@"&captcha_sid=%@&captcha_key=%@", captcha_sid, [self URLEncodedString: captcha_user]];
    }
    NSLog(@"Sending request: %@", reqURl);
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:reqURl] 
                                                            cachePolicy:NSURLRequestReloadIgnoringLocalCacheData 
                                                        timeoutInterval:60.0]; 
    
    // Для простоты используется обычный запрос NSURLConnection, ответ сервера сохраняем в NSData
    NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
    
    // Если ответ получен успешно, можем его посмотреть и заодно с помощью JSONKit получить NSDictionary
    if(responseData){
        NSDictionary *dict = [[JSONDecoder decoder] parseJSONData:responseData];
        
        // Если есть описание ошибки в ответе
        NSString *errorMsg = [[dict objectForKey:@"error"] objectForKey:@"error_msg"];
        
        NSLog(@"Server response: %@ \nError: %@", dict, errorMsg);
        
        // Если требуется ввод капчи. Тут я проверяю на строку Captcha needed, хотя лучше использовать код ошибки.
        if([errorMsg isEqualToString:@"Captcha needed"]){
            isCaptcha = YES;
            // Сохраняем параметры для капчи
            NSString *captcha_sid = [[dict objectForKey:@"error"] objectForKey:@"captcha_sid"];
            NSString *captcha_img = [[dict objectForKey:@"error"] objectForKey:@"captcha_img"];
            [[NSUserDefaults standardUserDefaults] setObject:captcha_img forKey:@"captcha_img"];
            [[NSUserDefaults standardUserDefaults] setObject:captcha_sid forKey:@"captcha_sid"];
            // Сохраняем url запроса чтобы сделать его повторно после ввода капчи
            [[NSUserDefaults standardUserDefaults] setObject:reqURl forKey:@"request"];
            [[NSUserDefaults standardUserDefaults] synchronize];
            
            [self getCaptcha];
        }
        
        return dict;
    }
    return nil;
}

Функция возвращает NSDictionary ответ сервера, для его формирования используется JSONKit, так как по-умолчанию ВКонтакте отвечает в формате JSON.

Captcha
Если вдруг сервер решил, что пользвателю нужно ввести капчу, то он, в ответ на запрос, вернет ошибку с текстом: Captcha needed и параметрами – captcha_sid (это id капчи), captcha_img (ссылка на изображение капчи). Вооружившись этими параметрами и заодно сохранив запрос, по которому сервер нам так ответил, мы вызываем функцию ввода капчи:

[self getCaptcha];

Рассмотрим ее чуть подробнее:

- (void) getCaptcha {

    NSString *captcha_img = [[NSUserDefaults standardUserDefaults] objectForKey:@"captcha_img"];
    UIAlertView *myAlertView = [[UIAlertView alloc] initWithTitle:@"Введите код:\n\n\n\n\n"
                                                          message:@"\n" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil];
    
    UIImageView *imageView = [[[UIImageView alloc] initWithFrame:CGRectMake(12.0, 45.0, 130.0, 50.0)] autorelease];
    imageView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:captcha_img]]];
    [myAlertView addSubview:imageView];
    
    UITextField *myTextField = [[[UITextField alloc] initWithFrame:CGRectMake(12.0, 110.0, 260.0, 25.0)] autorelease];
    [myTextField setBackgroundColor:[UIColor whiteColor]];
    
    // Отключаем автокорректировку
    myTextField.autocorrectionType = UITextAutocorrectionTypeNo;
    // Отключаем автокапитализацию
    myTextField.autocapitalizationType = UITextAutocapitalizationTypeNone;
    myTextField.tag = 33;
    
    [myAlertView addSubview:myTextField];
    [myAlertView show];
    [myAlertView release];
}

- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if(isCaptcha && buttonIndex == 1){
        isCaptcha = NO;
        
        UITextField *myTextField = (UITextField *)[actionSheet viewWithTag:33];
        [[NSUserDefaults standardUserDefaults] setObject:myTextField.text forKey:@"captcha_user"];
        NSLog(@"Captcha entered: %@",myTextField.text);
        
        // Вспоминаем какой был последний запрос и делаем его еще раз
        NSString *request = [[NSUserDefaults standardUserDefaults] objectForKey:@"request"];
        
        NSDictionary *newRequestDict =[self sendRequest:request withCaptcha:YES];
        NSString *errorMsg = [[newRequestDict  objectForKey:@"error"] objectForKey:@"error_msg"];
        if(errorMsg) {
            [self sendFailedWithError:errorMsg];
        } else {
            [self sendSuccessWithMessage:@"Капча обработана успешно и запрос выполнен!"];
        }
    }
}

Используя стандартный UIAlertView, с добавлением UIImageView и UITextField, и параметр captcha_img, мы даем пользователю возможность ввести капчу. После того как капча введена, в функции делегата UIAlertView сохраняем то, что ввел пользователь в NSUserDefaults с ключем captcha_user и используя ранее сохраненный url запроса, делаем его повторно, на этот раз указав в параметре withCaptcha: YES. В итоге, перед отправкой запроса, к нему добавляюся параметы captcha_sid и captcha_key (то что ввел пользователь):

- (NSDictionary *) sendRequest:(NSString *)reqURl withCaptcha:(BOOL)captcha {
    // Если это запрос после ввода капчи, то добавляем в запрос параметры captcha_sid и captcha_key
    if(captcha == YES){
        NSString *captcha_sid = [[NSUserDefaults standardUserDefaults] objectForKey:@"captcha_sid"];
        NSString *captcha_user = [[NSUserDefaults standardUserDefaults] objectForKey:@"captcha_user"];
        // Добавляем к запросу данные для капчи. Не забываем, что введенный пользователем текст нужно обработать.
        reqURl = [reqURl stringByAppendingFormat:@"&captcha_sid=%@&captcha_key=%@", captcha_sid, [self URLEncodedString: captcha_user]];
    }
...

Капча введена, запрос отправлен, текст должен быть успешно размещен на стене пользователя!

2.2 Отправка изображения на стену
Часто встречается необходимость разместить фото из приложения на стене пользователя. Чтобы решить эту задачу нужно пройти следующие этапы:

  1. Запрос url сервера ВКонтакте для загрузки нашего изображения (photos.getWallUploadServer)
  2. По полученной ссылке в ответе сервера отправляем изображение методом POST
  3. Получив в ответе hash, photo, server, отправлем команду на сохранение фото на стене (photos.saveWallPhoto)
  4. Получив в ответе photo id, делаем запрос на размещение на стене картинки с помощью wall.post, где в качестве attachment указываем photo id

2.2.1 Получение url сервера ВКонтакте для загрузги изображения

- (IBAction)sendImageAction:(id)sender {
    if(!isAuth) return;
    UIImage *image = [UIImage imageNamed:@"test.jpg"];
    NSString *user_id = [[NSUserDefaults standardUserDefaults] objectForKey:@"VKAccessUserId"];
    NSString *accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:@"VKAccessToken"];
    
    // Этап 1 
       
    NSString *getWallUploadServer = [NSString stringWithFormat:@"https://api.vk.com/method/photos.getWallUploadServer?owner_id=%@&access_token=%@", user_id, accessToken];
    
    NSDictionary *uploadServer = [self sendRequest:getWallUploadServer withCaptcha:NO];
    
    // Получаем ссылку для загрузки изображения
    NSString *upload_url = [[uploadServer objectForKey:@"response"] objectForKey:@"upload_url"];

...

Теперь, получив ссылку для загрузки изображения, нам нужно сделать POST запрос с вложенным изображением. Для этого изображение преобразуем в NSData и создаем запрос с помощью функции

[self sendPOSTRequest:upload_url withImageData:imageData];

2.2.2 Формируем POST запрос

...
// Этап 2 
    // Преобразуем изображение в NSData
    NSData *imageData = UIImageJPEGRepresentation(image, 1.0f);
    
    NSDictionary *postDictionary = [self sendPOSTRequest:upload_url withImageData:imageData];
    
    // Из полученного ответа берем hash, photo, server 
    NSString *hash = [postDictionary objectForKey:@"hash"];
    NSString *photo = [postDictionary objectForKey:@"photo"];
    NSString *server = [postDictionary objectForKey:@"server"];
...

Функцию формирующую POST-запрос вы можете посмотреть в примере.

2.2.3 Создаем запрос на сохранение фото на сервере ВКонтакте

...
// Этап 3 
    // Создаем запрос на сохранение фото на сервере вконтакте, в ответ получим id фото
    NSString *saveWallPhoto = [NSString stringWithFormat:@"https://api.vk.com/method/photos.saveWallPhoto?owner_id=%@&access_token=%@&server=%@&photo=%@&hash=%@", user_id, accessToken,server,photo,hash];
    
    NSDictionary *saveWallPhotoDict = [self sendRequest:saveWallPhoto withCaptcha:NO];
    
    NSDictionary *photoDict = [[saveWallPhotoDict objectForKey:@"response"] lastObject];
    NSString *photoId = [photoDict objectForKey:@"id"];
...

В ответ получаем photo id загруженной фотографии, теперь осталось сделать обычный запрос wall.post, где в качестве параметра attachment указать photo id. Если нужно еще добавить ссылку, то достаточно после photo id, через запятую указать ее.

2.2.4 Размещаем фото на стене

...
// Этап 4 
    // Постим изображение на стену пользователя
     NSString *postToWallLink = [NSString stringWithFormat:@"https://api.vk.com/method/wall.post?owner_id=%@&access_token=%@&message=%@&attachment=%@", user_id, accessToken, [self URLEncodedString:@"К изображению можно добавить текст и ссылку"], photoId];
    
    NSDictionary *postToWallDict = [self sendRequest:postToWallLink withCaptcha:NO];
    NSString *errorMsg = [[postToWallDict  objectForKey:@"error"] objectForKey:@"error_msg"];
    if(errorMsg) {
        [self sendFailedWithError:errorMsg];
    } else {
        [self sendSuccessWithMessage:@"Картинка размещена на стене!"];
    }
    // Ура! Фото должно быть на стене!

Часть 3. Logout пользователя.
Чтобы сделать logout достаточно отправить на сервер ВКонтакте запрос:

NSString *logout = @"http://api.vk.com/oauth/logout";

Пример функции logout:

- (IBAction)logout:(id)sender {
    // Запрос на logout
    NSString *logout = @"http://api.vk.com/oauth/logout";
    
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:logout] 
                                                            cachePolicy:NSURLRequestReloadIgnoringLocalCacheData 
                                                        timeoutInterval:60.0]; 
    NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
    if(responseData){
        NSDictionary *dict = [[JSONDecoder decoder] parseJSONData:responseData];
        NSLog(@"Logout: %@", dict);
        
        // Приложение больше не авторизовано, можно удалить данные
        isAuth = NO;
        [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"VKAccessUserId"];
        [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"VKAccessToken"];
        [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"VKAccessTokenDate"];
        [[NSUserDefaults standardUserDefaults] synchronize];
        
        [self sendSuccessWithMessage:@"Выход произведен успешно!"]; 
    }
}

Несмотря на то, что ВКонтакте отвечает ошибкой, выход пользователя все-таки происходит :)

Logout: {
    error = "invalid_client";
    "error_description" = "client_id is incorrect";
}

Заключение.
Надеюсь, что эта статья поможет вам в освоении API Вконтакте. Буду рад комментариям, дополнениям.
Благодарости готов принять в виде инвайта на хабр и лепру :)

4 News программа новостей для ipad

Моя программа в App store!

Сегодня моя программа 4 News наконец-то прошла проверку в apple и была размещена в App store! В сумме на проверку у apple ушло 8 дней, из них 7 дней очереди и один день самого ревью. Радует, что с первого раза без ошибок прошло ревью. Программу можно посмотреть здесь – iTunes.

HTML-парсер для iOS

У меня ушло много времени на поиски простого и эффективного решения для парсинга html в iOS, пробовал кучу вариантов, от работы с NSString до зубодробительных regexp и долго не находилось ничего путного. Пока однажды не набрел на https://github.com/zootreeves/Objective-C-HMTL-Parser. Простой и эффективный wrapper для работы с html.

Установка:
1. Скачиваем проект по ссылке выше. Разархивируем и кидаем все .h и .m файлы в наш проект
2. В project settings в разделе «header search paths» прописываем «/usr/include/libxml2»
3. В папку Frameworks нажимаем «Add -> Existing Frameworks» и в списке выбираем libxml2.dylib

Использование:

        NSError * error = nil;
	HTMLParser * parser = [[HTMLParser alloc] initWithContentsOfURL:[NSURL URLWithString:@"http://www.yandex.ru"] error:&error];	
	if (error) {
		NSLog(@"Error: %@", error);
		[parser release];
		parser = nil;
		return;
	}
	HTMLNode * bodyNode = [parser doc]; // получаем родительский элемент
        
        HTMLNode *mynode = [bodyNode findChildWithAttribute:@"id" matchingName:@"all" allowPartial:TRUE]; // Берем div с id="all"
        NSArray *newsList = [mynode findChildTags:@"li"]; // получаем NSArray HTMLNode элеметнов содержащих li тэги с новостями на главной
        for (HTMLNode *news in newsList) { // Пробегаем по списку тэгов и выводим новости
            NSLog(@"Новость: %@", [news allContents]); // выводим текст из HTMLNode news и всех children
        }

        [parser release]; // освобождаем память

Полный список методов прокомментирован в .h файлах, все предельно просто. :)
Так же инструкция на английском есть на блоге автора – [link].
Парсер сделан на основе libxml и если что можно дописать свои методы. Все благодарности его автору :)

Функция поиска url изображений в rss

Довольно простая и удобная фунцкия, оказалась полезна когда нужно достать url картинки из текста в rss-рассылке, чтобы использовать ее как миниатюру.

- (NSString *)getFirstImageUrl: (NSString *) html {
    NSScanner *theScanner;
    NSString *text = nil;
	if(html == nil) return nil;
    theScanner = [NSScanner scannerWithString: html];
	
    // находим начало тэга
    [theScanner scanUpToString: @"

Так же можно добавить разные проверки на наличие/отсутствие кавычек в src и прочее. Основной принцип, думаю понятен :)

Как добавить поддержку жестов в UIWebView

На просторах интернета мне встретилось множество способов добавления жестов для UIWebView, большинство из них были слишком перегружены, создавали лишние UIView и при этом терялась функциональность  самого UIWebView. Вот и решил описать способ, который намного проще и эффективней решает эту задачу.

В UIViewController, в котором лежит нужный UIWebView, добавляем в .h файл:

В файл .m добавляем (например в viewDidLoad):

-(void) viewDidLoad {
        [super viewDidLoad];
        // Создаем жест – движение вправо, цепляем его на функцию swipeRightAction
	UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeRightAction:)];
	swipeRight.direction = UISwipeGestureRecognizerDirectionRight; // направление жеста
	swipeRight.delegate = self; // делаем наш UIViewController делегатом
	swipeRight.numberOfTouchesRequired = 2; // указываем сколько одновременных касаний нужно для активации жеста
        [webView addGestureRecognizer:swipeRight]; // добавляем жест в webView
	[swipeRight release]; // не забываем делать release, функция  addGestureRecognizer делает retain для нас

        // Тоже самое для жеста влево
	UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeLeftAction:)];
	swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
	swipeLeft.delegate = self;
        swipeLeft.numberOfTouchesRequired = 2; // указываем сколько одновременных касаний нужно для активации жеста
	[webView addGestureRecognizer:swipeLeft];
        [swipeLeft release];
}

// Добавляем метод протокола UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
	return YES;
}

// Ну и сами обработчики событий
- (void)swipeRightAction:(id)obj
{
	NSLog(@"Right swipe");
}

- (void)swipeLeftAction:(id)obj
{
	NSLog(@"Left swipe");
}

Вот и все! Таким вот простым способом, можно добавить функциональности программе, главное не перебарщивать с жестами :)

Мой блог

Запускаю свой блог по разработке приложений для iphone, ipad. В разработке находится приложение для ipad, которое скоро будет анонсировано.

Здесь буду писать на тему разработки и программирования на objective-c.