Обработка данных, возвращаемых из нескольких объектов NSOperation в объекте NSOperation, который зависит от них - PullRequest
2 голосов
/ 17 августа 2011

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

Рис 1.


В целях визуализации рассмотрим пример с ASIHTTPRequests A, B, C, D, E и F:

URL-адрес A зависит от результата B и C,

и URL B зависит от результата D, E и F.

B и C могут быть вычислены одновременно, как и D, E и F.

NSOperationQueue = [(D, E, F), (B, C), A]


Пока что я создал NSOperationQueue, который содержит дерево зависимостей запросов ASIHTTP. Однако URL-адреса запросов ASIHTTP должны зависеть от результатов предыдущих операций, а прямо сейчас - нет.

Вопрос: Как лучше всего передать результаты вычислений, выполненных несколькими операциями NSO, в операцию NSO, которая зависит от них, и как я могу настроить это с помощью ASIHTTPRequests?

Заранее спасибо, Джулиан Цейпек

Ответы [ 2 ]

1 голос
/ 17 августа 2011

В итоге я решил эту проблему, обернув ASIHTTPRequest в пользовательский объект NSOperation, который заполнил запрос таким образом, что пользовательский запрос B содержал указатель на объект в D, E и словарь UserInfo для ASIHTTPRequest F.Хотя мне понравилось решение @ JosephH, я не мог понять, как легко сгенерировать словарь или массив с неповрежденным деревом зависимостей.

Ниже приведена упрощенная версия моего пользовательского объекта NSOperationObject;любые предложения приветствуются.Я широко использовал Руководство по программированию параллелизма Apple в качестве справочного материала, но поскольку у меня не было никакого предшествующего опыта по расширению класса NSOperation, я уверен, что есть лучший способ сделать это.

#import <Foundation/Foundation.h>
#import "SyncableData.h"
#import "ASIHTTPRequest.h"

@interface PushContentRequest : NSOperation <ASIHTTPRequestDelegate> {
    BOOL executing;
    BOOL finished;
    id <SyncableData> data;
    ASIHTTPRequest *request;
    NSURL *url;
    id <ASIHTTPRequestDelegate> delegate;
}

- (id)initWithDataObject:(id <SyncableData>)theData url:(NSURL *)theUrl delegate:(id <ASIHTTPRequestDelegate>)theDelegate;

@end


#import "PushContentRequest.h"

@implementation PushContentRequest

- (id)initWithDataObject:(id <SyncableData>)theData url:(NSURL *)theUrl delegate:(id <ASIHTTPRequestDelegate>)theDelegate {
    if ((self = [super init])) {
        executing = NO;
        finished = NO;
        data = [theData retain];
        url = [theUrl retain];
        delegate = [theDelegate retain];
    }
    return self;
}

- (BOOL)isConcurrent {
    return YES;
}

- (BOOL)isExecuting {
    return executing;
}

- (BOOL)isFinished {
    return finished;
}

- (void)start {
    if ([self isCancelled]) {
        [self willChangeValueForKey:@"isFinished"];
        finished = YES;
        [self didChangeValueForKey:@"isFinished"];
        return;
    }

    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    request = [ASIHTTPRequest requestWithURL:url];
    NSString *xmlToPost = [[NSString alloc] initWithString: [theData getXMLRep]];
    [request appendPostData:[xmlToPost dataUsingEncoding:NSUTF8StringEncoding]];
    [request setDelegate:self];
    NSDictionary *userInfoDict = [[NSDictionary alloc] initWithObjectsAndKeys:data, @"theData", nil];
    [request setUserInfo:userInfoDict];
    [userInfoDict release];
    [xmlToPost release];
    [self willChangeValueForKey:@"isExecuting"];
    [request start];
    executing = YES;
    [self didChangeValueForKey:@"isExecuting"];
    [pool release];

}

- (void)dealloc {
    [delegate release];
    [url release];
    [data release];
    [super dealloc];
}

- (void)requestFinished:(ASIHTTPRequest *)therequest {
    [delegate requestFinished:therequest];

    [self willChangeValueForKey:@"isFinished"];
    [self willChangeValueForKey:@"isExecuting"];

    executing = NO;
    finished = YES;

    [self didChangeValueForKey:@"isExecuting"];
    [self didChangeValueForKey:@"isFinished"];
}

- (void)requestFailed:(ASIHTTPRequest *)therequest {
    [delegate requestFailed:therequest];
    [self willChangeValueForKey:@"isFinished"];
    [self willChangeValueForKey:@"isExecuting"];

    executing = NO;
    finished = YES;

    [self didChangeValueForKey:@"isExecuting"];
    [self didChangeValueForKey:@"isFinished"];
}

@end

Делегат этого PushContentRequest в настоящее время обрабатывает интерпретацию словаря UserInfo словаря ASIHTTPRequest и запрос в моей реализации, хотя я полагаю, что может иметь больше смысла выполнять эту обработку в теле PushContentRequest.

1 голос
/ 17 августа 2011

Я бы сделал следующее.

Для начала очередь:

D, E, F и C

В обратном вызове делегата requestFinished для D, E &F, проверьте, завершены ли остальные все 3 запроса, если это так, отправьте B.

Сделайте то же самое для обратных вызовов для B & C - если они оба закончили, отправьте A.

Вам понадобится какой-нибудь объект, который будет использоваться всеми запросами для сохранения результатов / статуса предыдущих запросов.

...