Главная » iPhone, Objective-C, Программирование для iOS и MacOS » Вспомогательные  объекты Objective-C

0

Таймеры просты. Они умеют делать только одно: срабатывать в нужный момент. Поэтому модель «приемник/действие» хорошо подходит для них. Многие простые элементы пользовательского интерфейса (такие, как кнопки и шкалы) тоже используют механизм «приемник/действие». А как насчет чего-то более сложного?

В главе 23 мы использовали объект NSURLConnection для загрузки данных с веб-сервера. Программа работала, но у такого решения есть два недостатка:

•  Главный программный поток блокируется в ожидании поступления данных. Если бы этот метод использовался в настоящем приложении, пользовательский интерфейс переставал бы реагировать на действия пользователя до момента получения данных.

•  Метод не предусматривает возможность обратного вызова – например, на случай, если веб-сервер запросит имя пользователя и пароль.

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

Как получить эти обратные вызовы? Для этого NSURLConnection передается

вспомогательный объект. Когда в ходе загрузки что-то происходит, подключение передает сообщения вспомогательному объекту. Какие сообщения? Создатель класса NSURLConnection определил протокол (список объявлений методов), которые могут быть реализованы вспомогательным объектом. Некоторые методы этого протокола:

-­‐ (NSURLRequest *)connection:(NSURLConnection *)c willSendRequest:(NSURLRequest  *)req redirectResponse:(NSURLResponse  *)res;

-­‐   (void)connection:(NSURLConnection  *)sender didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge       *)ch;

-­‐   (void)connection:(NSURLConnection  *)sender didReceiveData:(NSData    *)data;

-­‐      (void)connectionDidFinishLoading:(NSURLConnection     *)sender;

-­‐   (void)connection:(NSURLConnection  *)sender  didFailWithError:(NSError  *)error;

-­‐   (NSCachedURLResponse  *)connection:(NSURLConnection  *)sender willCacheResponse:(NSCachedURLResponse      *)cachedResponse;

Как видите, NSURLConnection живет куда более интересной жизнью, чем NSТimer. Сейчас мы создадим объект, который реализует часть методов этого протокола, и представим его NSURLConnection как вспомогательный объект. Для этой цели у NSURLConnection имеется делегат, на который ссылается указатель с именем delegate.

запрос

Рис. 2.4.4. Logger – делегат объекта NSUrlConnection

в main() создайте объект NSURLConnection и назначьте экземпляр Logger его делегатом:

#import <Foundation/Foundation.h>

#import "Logger.h"

int main (int argc, const char * argv[])

{

@autoreleasepool {

Logger *logger = [[Logger alloc] init]; NSURL *url = [NSURL URLWithString:

@"http://www.gutenberg.org/cache/epub/205/pg205.txt"];

NSURLRequest *request = [NSURLRequest requestWithURL:url];

    unused NSURLConnection *fetchConn

= [[NSURLConnection alloc] initWithRequest:request delegate:logger

startImmediately:YES];

    unused NSTimer *timer

= [NSTimer scheduledTimerWithTimeInterval:2.0

target:logger selector:@selector(sayOuch:) userInfo:nil

repeats:YES];

[[NSRunLoop currentRunLoop] run];

}

return 0;

}

Экземпляру  Logger понадобится  экземпляр  NSМutаblеDаtа для  хранения поступающих   байтов.   Включите   соответствующую   переменную   экземпляра   в

Logger.h:

#import <Foundation/Foundation.h>

@interface Logger : NSObject { NSMutableData *incomingData;

}

-­‐    (void)sayOuch:(NSTimer  *)t;

@end

Теперь реализуйте некоторые методы делагата в Logger.m:

#import "Logger.h"

@implementation Logger

-­‐   (void)sayOuch:(NSTimer  *)t

{

NSLog(@"Ouch!");

}

// вызывается при каждом получении блока данных

-­‐   (void)connection:(NSURLConnection  *)connection didReceiveData:(NSData   *)data

{

NSLog(@"received %lu bytes", [data length]);

// если изменяемый объект данных не существует, создать его if (!incomingData) {

incomingData = [[NSMutableData alloc] init];

}

[incomingData appendData:data];

}

// вызывается при обработке последнего блока

-­‐       (void)connectionDidFinishLoading:(NSURLConnection     *)connection

{

NSLog(@"Got it all!");

NSString *string = [[NSString alloc] initWithData:incomingData

encoding:NSUTF8StringEncoding];

incomingData = nil;

NSLog(@"string has %lu characters", [string length]);

// раскоментируйте следующую строку, чтобы увидеть весь файл

// NSLog(@"The whole string is %@", string);

}

// вызывается в случае ошибки при загрузке данных

-­‐   (void)connection:(NSURLConnection  *)connection didFailWithError:(NSError    *)error

{

NSLog(@"connection failed: %@", [error localizedDescription]); incomingData = nil;

}

@end

Обратите  внимание:  мы  реализуем  не  все  методы  протокола,  а  только  те, которые важны для нашей программы.

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

Итак, до настоящего момента мы видим следующие правила обратного вызова: при отправке одного обратного вызова одному объекту Apple использует механизм

«приемник/действие». При отправке различных вызовов одному объекту Apple использует вспомогательный объект с протоколом. (Протоколы более подробно рассматриваются в следующей главе.) Вспомогательные объекты обычно называются делегатами или источниками данных.

А если обратный вызов должен передаваться нескольким объектам?

Источник: Аарон Хилегас, «Objective-C. Программирование для iOS и MacOS», 2012 г.

По теме:

  • Комментарии