Дизайн iOS: использование шаблона делегата в библиотеке - PullRequest
2 голосов
/ 18 октября 2010

У меня есть библиотечный проект, который использует ASIHTTPRequest для выполнения URL-запросов и анализа ответов.Библиотека будет использоваться отдельным проектом приложения для iPhone.

Если код моего контроллера iPhone отвечает на событие касания, а затем вызывает библиотеку для выполнения запросов URL-адресов, как лучше выполнить запросы асинхронно?

Если в библиотеке я использую шаблон делегата для асинхронных запросов, как показано в примере кода ASIHTTPRequest, как я могу вернуть данные из библиотеки обратно в код вызова в контроллере iPhone?

ЕслиВместо этого я делаю синхронные URL-запросы с помощью ASIHTTPRequest внутри библиотеки. Какой самый простой способ поместить вызовы библиотеки из контроллера iPhone в отдельный поток, чтобы избежать связывания потока пользовательского интерфейса?

Ответы [ 2 ]

2 голосов
/ 19 октября 2010

Я не эксперт по ASIHTTPRequest (NSURLRequest всегда справлялся со мной), но после быстрого взгляда на код, похоже, что вы использовали бы его делегат и свойства didFinishSelector, чтобы дать кому-то возможность сообщить, когда запрос URL законченный. Так, например:

- (void)startURLRequest
{
    ASIHTTPRequest *myRequest;

    /* code to set the request up with your target URL, etc here */

    myRequest.delegate = self;
    myRequest.didFinishSelector = @selector(HTTPRequestDidFinish:);

    /* ... */

    [myRequest startAsynchronous];
}

- (void)HTTPRequestDidFinish:(ASIHTTPRequest *)request
{
    NSLog(@"Request %@ did finish, got data: %@", request, request.data);
    [myTargetForData didReceiveData:request.data fromURL:request.originalURL];
}

Apple явно рекомендует использовать встроенные механизмы стиля runloop для асинхронной выборки HTTP, а не отдельных потоков. Использование отдельных потоков может привести к снижению производительности - по крайней мере, с точки зрения срока службы батареи и / или нагрева устройства, даже если это все еще достаточно быстро.

Тем не менее, в качестве точки обучения, безусловно, самый быстрый способ переключить что-либо в отдельный поток и сделать так, чтобы он возвращался в основной поток (помните: объекты UIKit могут передаваться только из основного потока), это изменить это :

- (void)postResult:(NSString *)result
{
    instanceOfUILabel.text = result;
}

- (void)doExpensiveOperationOn:(NSString *)source
{
     /* lots of expensive processing here, and then... */
     [self postResult:result];
}

- (IBAction)userWantsOperationDone:(id)sender
{
     [self doExpensiveOperationOn:@"some value or another"];
}

В это:

- (void)postResult:(NSString *)result
{
    instanceOfUILabel.text = result;
}

- (void)doExpensiveOperationOn:(NSString *)source
{
     /* we're on a thread without an autorelease pool now, probably we'll want one */
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

     /* lots of expensive processing here, and then... */

     /* in this simplified example, we assume that ownership of 'result' is here on this thread, possibly on the autorelease pool, so wait until postResult has definitely finished before doing anything that might release result */
     [self performSelectorOnMainThread:@selector(postResult:) withObject:result waitUntilDone:YES];

     [pool release];
}

- (IBAction)userWantsOperationDone:(id)sender
{
     [self performSelectorOnBackgroundThread:@selector(doExpensiveOperationOn:) withObject:@"some value or another"];
}

Существует около миллиона возможных ошибок параллелизма, которые вы можете совершить, просто перейдя в поток, даже не задумываясь об этом, и в этом примере очевидная проблема заключается в том, что то, что вызвало IBAction, может [вероятно] вызвать его еще несколько раз, прежде чем doExblyOperationOn завершится. Многопоточность - это не то, с чем нужно легко разбираться.

1 голос
/ 25 октября 2010

Для чьей-либо будущей ссылки, самый простой подход, который я нашел, состоит в том, чтобы использовать функциональность асинхронного запроса, встроенную в ASIHTTPRequest, устанавливая объект моей библиотеки в качестве делегата и устанавливая значения didFinishSelector: и didFailSelector: для различных методов внутри моей библиотеки для каждого запроса.

В конце обработки каждого ответа я назначаю проанализированный ответ (NSString * или NSArray *) свойству моего библиотечного объекта вместо возврата значения.

Когда мое представление iOSзагружен делегат контроллера, я добавляю наблюдателя изменений в каждое из свойств библиотеки, используя Наблюдение значения ключа .Когда ответ анализируется и присваивается свойству в библиотеке, в коде моего делегата контроллера представления вызывается наблюдательValueForKeyPath: ofObject: change: context: метод, и оттуда я могу выяснить, какое свойство было изменено и, следовательно, какой пользовательский интерфейснуждается в обновлении.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...