-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

在您的情况下,我将使用索引遍历用户数组,然后仅针对最后一个索引,在您的完成块中执行一个分支,例如:

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

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

WhereloopFullyExecuted封装了循环完全完成后你需要做的事情(包括完成块)。

编辑:如果您希望在 for 循环中的每次迭代中您的程序“等待”完成块完全执行,那么方法需要完全不同。

你需要的是定义一个方法来处理一个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 回答
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.

使用这种方法,您不必担心请求完成的顺序。如果您在最后一个用户的请求处理程序块中调用完成块,您可能会过早地调用它,例如,如果倒数第二个请求比最后一个请求花费更长的时间(异步执行总是可能发生)。

于 2013-01-06T13:42:57.890 回答