1

私のアプリはこのように動作しています: - アルバムを作成して写真を撮ります - サーバーに送信します - 写真分析後に回答/補足情報を取得します。

送信部分に問題があります。ここにコードがあります

@interface SyncAgent : NSObject <SyncTaskDelegate>

@property  NSOperationQueue* _queue;
-(void)launchTasks;

@end


@implementation SyncAgent

@synthesize _queue;

- (id)init
{
    self = [super init];
    if (self) {
        self._queue = [[NSOperationQueue alloc] init];
        [self._queue setMaxConcurrentOperationCount:1];
    }
    return self;
}

-(void) launchTasks {

    NSMutableArray *tasks = [DataBase getPendingTasks];

    for(Task *t in tasks) {
        [self._queue addOperation:[[SyncTask alloc] initWithTask:t]];
    }
}
@end

および SyncTask :

@interface SyncTask : NSOperation

@property (strong, atomic) Task *_task;
-(id)initWithTask:(Task *)task;
-(void)mainNewID;
-(void)mainUploadNextPhoto:(NSNumber*)photoSetID;

@end

@implementation SyncTask

@synthesize _task;

-(id)initWithTask:(Task *)task {
    if(self = [super init]) {
        self._task = task;
    }
    return self;
}

-(void)main {

    NSLog(@"Starting task : %@", [self._task description]);
    // checking if everything is ready, sending delegates a message etc

    [self mainNewID];
}

-(void)mainNewID {

    __block SyncTask *safeSelf = self;

    [[WebAPI sharedClient] createNewPhotoSet withErrorBlock:^{
        NSLog(@"PhotoSet creation : error")
    } andSuccessBlock:^(NSNumber *photoSetID) {
        NSLog(@"Photoset creation : id is %d", [photoSetID intValue]);
        [safeSelf mainUploadNextPhoto:photoSetID];
    }];
}

-(void)mainUploadNextPhoto:(NSNumber*) photoSetID {

    //just admit we have it. won't explain here how it's done
    NSString *photoPath;

    __block SyncTask *safeSelf = self;

    [[WebAPI sharedClient] uploadToPhotosetID:photoSetID withPhotoPath:photoPath andErrorBlock:^(NSString *photoPath) {
        NSLog(@"Photo upload error : %@", photoPath);

    } andSuccessBlock:^(NSString *photoPath) {

        NSLog(@"Photo upload ok : %@", photoPath);
        //then we delete the file
        [safeSelf mainUploadNextPhoto:photoSetID];
    }];
}
@end

すべてのネットワーク操作は、次のように AFNetworking を使用して行われます。

-(void)myDummyDownload:(void (^)(NSData * data))successBlock
{
    AFHTTPClient* _httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:@"http://www.google.com/"]];
    [_httpClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];

    NSMutableURLRequest *request = [_httpClient requestWithMethod:@"GET" path:@"/" nil];
    [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

    AFHTTPRequestOperation *operation = [_httpClient HTTPRequestOperationWithRequest:(NSURLRequest *)request
        success:^(AFHTTPRequestOperation *operation, id data) {
            if(dataBlock)
                dataBlock(data);
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            NSLog(@"Cannot download : %@", error);
    }];

    [operation setShouldExecuteAsBackgroundTaskWithExpirationHandler:^{
        NSLog(@"Request time out");
    }];

    [_httpClient enqueueHTTPRequestOperation:operation];
}

私の問題は次のとおりです。私の接続は非同期で行われるため、前のタスクが終了するのを待たずにすべてのタスクが一緒に起動さ[self._queue setMaxConcurrentOperationCount:1]SyncAgentます。

すべての接続を同期的に実行する必要がありますか? 接続をこの方法で行うべきではなく、これらのメソッドを他の場所で使用してバックグラウンドで実行する必要がある可能性があるため、これは良い考えではないと思いますが、より良い方法を見つけることができません。何か案が ?

ああ、私のコードにエラー/タイプミスがある場合は、貼り付ける前に要約しようとしたときに表示されたことを保証できます。今のところ問題なく動作しています。

ありがとう !

PS: 問題を説明するより良い方法を見つけられなかった長い貼り付けで申し訳ありません。

編集:セマフォを使用する方がセットアップと理解が簡単であることがわかりました:非同期にディスパッチされたブロックが完了するのを待つにはどうすればよいですか?

4

2 に答える 2

2

サーバーを制御できる場合は、複数の同時アップロードをサポートするために、任意の順序で写真をアップロードできる API を作成することを検討する必要があります (大規模なバッチではかなり高速になる可能性があります)。

しかし、同期をとらなければならない場合、おそらく最も簡単な方法は、新しいリクエストをリクエストの完了ブロックにエンキューすることです。すなわち

// If [operations length] == 1, just enqueue it and skip all of this
NSEnumerator *enumerator = [operations reverseObjectEnumerator];
AFHTTPRequestOperation *currentOperation = nil;
AFHTTPRequestOperation *nextOperation = [enumerator nextObject]; 
while (nextOperation != nil && (currentOperation = [enumerator nextObject])) {
  currentOperation.completionBlock = ^{
    [client enqueueHTTPRequestOperation:nextOperation];
  }
  nextOperation = currentOperation;
}
[client enqueueHTTPRequestOperation:currentOperation];
于 2012-07-04T14:13:22.083 に答える
1

次のコードは私には有効ですが、欠点はわかりません。塩を少し入れてください。

 - (void) main {

  NSCondition* condition = [[NSCondition alloc] init];  
  __block bool hasData = false;
  [condition lock];

  [[WebAPI sharedClient] postPath:@"url" 
                        parameters:queryParams 
                           success:^(AFHTTPRequestOperation *operation, id JSON) {
                             //success code
                             [condition lock];
                             hasData = true;
                             [condition signal];
                             [condition unlock];

                           } 
                           failure:^(AFHTTPRequestOperation *operation, NSError *error) {

                             //failure code

                             [condition lock];
                             hasData = true;
                             [condition signal];
                             [condition unlock];
                           }];

  while (!hasData) {
    [condition wait];
  }
  [condition unlock];

}
于 2012-07-12T08:50:41.300 に答える