Несколько асинхронных запросов веб-сервиса NSURLConnection iOS - PullRequest
5 голосов
/ 13 мая 2011

У меня проблема в том, что я не знаю, как ее решить.Я могу без проблем отправлять запросы в службу REST при прохождении одного запроса.

Моя проблема сейчас заключается в том, что в зависимости от ответа я получаю некоторые значения, включая ID.Все полученные идентификаторы должны будут сделать еще один запрос для сбора новой информации.

Я предполагаю загрузить все конкретные запросы в массив или словарь и создать запрос из этого.У кого-нибудь есть полезные советы по этому поводу?Полученная информация затем заполнит UITableView.

Ответы [ 3 ]

4 голосов
/ 13 мая 2011

Я предлагаю вам использовать Sync-Async Pattern для этой проблемы.

Вам необходимо реализовать два синхронных метода:

// Fetch the array of ID's
-(NSArray*)fetchItemIDsWithError:(NSError**)error;

// Fetch the item for a ID
-(Item*)fetchItemForID:(NSString*)itemID error:(NSError**)error;

Их реализация с использованием синхронного кода проста и тестируема. Вы можете легко использовать простые методы, такие как dataWithURL…, stringWithContentsOfURL…, sendSynchronousRequest… или ASIHTTPrequest, и писать для этого прямые модульные тесты. Код также будет чрезвычайно прост в обслуживании и расширении, по сравнению с тем, как обычно заканчивается параллельный код.

Теперь на втором шаге создайте асинхронную оболочку, я бы использовал делегат и сигнатуру метода, подобную этой:

@protocol FetchItemsDelegate <NSObject>
-(void)didFetchItems:(NSArray*)array;
-(void)failedFetchItemsWithError:(NSError*)error;
@end

-(void)fetchItemsWithAsyncDelegate:(id<FetchItemsDelegate>)delegate;

У вас уже есть весь код, который делает то, что вам нужно, поэтому все, что вам нужно сделать, это устранить асинхронные части. Этот код будет хорошо отделен и прост. Пробалы не более этого:

-(void)fetchItemsWithAsyncDelegate:(id<FetchItemsDelegate>)delegate;
{
    [self performSelectorInBackground:@selector(backgroundFetchItemsWithDelegate:)
                           withObject:delegate];      
}

-(void)backgroundFetchItemsWithDelegate:(id<FetchItemsDelegate>)delegate;
{
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    BOOL success = YES;
    NSMutableArray* items = [NSMutableArray array];
    NSError* error = nil;
    NSArray* itemIDs = [self fetchItemIDsWithError:&error];
    if (itemIDs) {
        for (NSString* itemID in itemIDs) {
           Item* item = [self fetchItemForID:itemID
                                       error:&error];
           if (item) {
               [items addObject:item];
           } else {
               success = NO;
               break;
           }
        }
    } else {
        success = NO;
    }
    if (success) {
        [delegate performSelectorOnMainThread:@selector(didFetchItems:)
                                   withObject:[NSArray arraiWithArray:items]
                                waitUntilDone:NO];
    } else {
        [delegate performSelectorOnMainThread:@selector(failedFetchItemsWithError)
                                   withObject:error
                                waitUntilDone:NO];
    }
    [pool release];
}

Я написал более длинную запись в блоге на эту тему здесь: http://blog.jayway.com/2011/04/28/sync-asyn-pair-pattern-easy-concurrency-on-ios/

0 голосов
/ 13 мая 2011

Его решение зависит от вашей существующей реализации. (Я рассматриваю здесь только два случая.)

Дело I : If you are having a different class for managing connection related task, a separate class that has NSURLConnection Delegate methods.(Asynchronous..)

  • Вам нужно будет запустить цикл for для запроса всех запросов на 20 ID с регистрацией уведомления для них с ID в качестве имени уведомления. Когда соединение завершит свою загрузку, оно отправит уведомление вашему классу наблюдения, и здесь, используя имя уведомления, вы можете обновить соответствующее расписание соответствующего идентификатора. [здесь вам нужно будет создать различные объекты этого класса обработчика соединений] ... здесь вам нужно будет дождаться загрузки расписания, что вы можете сделать, вы можете поместить индикатор активности в дополнительное представление ячейки, пока расписание не загрузится (вы можете покажи имена в этом случае)

Дело II : If its singleton or in the same class which you are using.(we can not create it's multiple objects)..(it will have the performance cost.) one by one request.

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

Будет полезно, если вы напишите нам, как вы обрабатываете подключения.

Спасибо

0 голосов
/ 13 мая 2011

Ваш вопрос немного расплывчат, но я думаю, что могу понять вашу проблему. Обычно я выполняю шаблон делегата с протоколом при выполнении http-запросов:

@protocol HttpDelegate
   -(void) httpDidFinish;
   -(void) httpError:(NSError *) error;
@end

и в классе HttpClient:

-(void) connectionDidFinishLoading:(NSURLConnection *)connection {
    [self.delegate httpDidFinish];
}

Ваш контроллер (или другой класс) реализует HttpDelegate и в httpDidFinish либо делает второй запрос, либо заполняет вашу таблицу. В этом случае, поскольку это двухэтапный процесс, вместо реализации HttpDelegate в контроллере, я бы, вероятно, добавил еще один класс, TwoStepProcessor и TwoStepProcessorDelegate. TwoStepProcessorDelegate аналогичен HttpDelegate, за исключением того, что он имеет:

-(void) secondStepFinished:

, который реализует ваш контроллер.

...