-2

メソッド内に次のforループが含まれています。

—(void)_va1idateUsers:(NSArray *)users withCurrentAccount:(ACAccount *)account comp1etionB1ock:(void (“)(TSCSpamUser *user, NSError *error))comp1etionBlock; {

    for(TSCSpamUser *userID in users) {

        NSString *theID = (NSString*)userID;
        NSURL *ur1 = [NSURL URLwith5tring:[NSString stringWithFormat:@"https://api.twitter.com/1/users/show.json?user_id=%@&inc1ude_entities=true", theID]];
        SLRequest *request = [SLRequest requestForServiceType:SLServiceTypeTwitter
                                                requestMethod:5LRequestMethodGET
                                                          URL:ur1
                                                   parameters:nil];
        [request setAccount:account];
        [request performRequestwithHand1er:*(NSData *responseData, NSHTTPURLResponse *ur1Response, NSError *err0r) {

            if ([urlResponse statusCode] == 200) {
                TSCSpamUser *user = [[TSCSpamUser a11oc] initwithTwitterID:theID];

                user.level = 0;

                NSError *jsonError = nil;
                id jsonResu1t = [NSJSONSeria1ization JSON0bjectWithData:responseData options:0 error:&jsonError];
                if (jsonResu1t != nil) { ...... }
                else {
                    user.level = 0;
                }
            }
        }];

    }
}

このforループの終わりを検出する必要がありますが、forループの終わりだけではありません。完了ブロックは、forループが終了した後ではなく、最後の反復が開始されたときに呼び出されます。forループ内のすべても完了していることを確認する必要があります。これどうやってするの?

4

2 に答える 2

1

これは、ディスパッチグループの良いユースケースのように思えます。ループを開始する前に、を使用して新しいディスパッチグループを作成しますdispatch_group_create。ループ内dispatch_group_enterでは、すべてのリクエストに対してグループ()に入り、リクエストの完了ブロック内では、そのグループ(dispatch_group_leave)を離れます。ループの直後に呼び出しdispatch_group_notifyて、すべての要求が完了すると呼び出される完了ブロックをスケジュールします。

dispatch_group_t group = dispatch_group_create();

for (TCSpamUser *userID in users) {

    dispatch_group_enter( group );

    // ...
    [request performRequestWithHandler: ^ (...) {
        // ...
        dispatch_group_leave( group );
    }];
}

dispatch_group_notify( group, dispatch_get_main_queue(), ^{
    dispatch_release( group );
    completionBlock( user, error );
});

dispatch_group_enter対応するを呼び出すたびに確認してくださいdispatch_group_leave

この方法を使用すると、リクエストが完了する順序を気にする必要はありません。最後のユーザーのリクエストハンドラブロックで完了ブロックを呼び出すと、たとえば、最後から2番目のリクエストに最後のリクエストよりもはるかに長い時間がかかる場合(非同期実行では常に発生する可能性があります)、呼び出しが早すぎる可能性があります。

于 2013-01-06T13:42:57.890 に答える
1

あなたの場合、インデックスを使用してユーザーの配列を反復処理し、最後のインデックスに対してのみ、完了ブロックでブランチを実行します。例:

for (NSUInteger index = 0; index < [users count] ; ++index) {
   TSCSSpamUser* spamID = [users objectAtIndex:index];
   ...

   [request performRequestWithHandler.... : {
       ...
       if (index == [users count]-1) {
          [self loopFullyExecuted];
       }
    ...
}

ここloopFullyExecutedで、ループが完全に完了した後に実行する必要があることをカプセル化します(完了ブロックを含む)。

編集:forループの各反復で、プログラムが完了ブロックが完全に実行されるのを「待機」する場合は、アプローチを完全に変える必要があります。

必要なのは、1つを処理し、userID最終的にperformRequestを呼び出すメソッドを定義することです。

-(void) processUserID:(NSUInteger)index {
   TSCSSpamUser* spamID = [users objectAtIndex:index];
       ...
       [request performRequestWithHandler.... : {
       ...
           if (index < [users count])
              [self processUserID:index+1];
        }
    ...
}

ご覧のとおり、performRequest完了ブロックは次の反復を開始します。したがって、次の要素(存在する場合)は、前の要素の後にのみ処理されます。

次のコマンドを呼び出すことで、プロセス全体を開始します。

[self processUserID:0];
于 2013-01-06T12:42:16.273 に答える