2013-04-20 4 views
2

복수 비동기 요청을 수행하기 위해 NSURLConnection을 사용하고 있습니다. 수행해야 할 총 숫자에서 완료된 요청 수를 보여주는 진행률 표시기를 보여 드리고자합니다. 그러나 요청을 만들기 전에이 진행률 표시기를 설정하고 표시하려고하거나 요청을 수행하기 전에 호출 된 다른 메서드에서 표시하려고하면 표시되지 않습니다. 요청이 주석 처리되면 진행률 표시기가 잘 표시됩니다. 그러나 그렇지 않은 경우 Xcode는 비동기 요청을 받고 기본 스레드를 차단하여 UI 변경을 불가능하게하는 것처럼 보입니다. 비동기 요청의 블록 주석NSURLConnection sendAsynchronousRequest : 메인 스레드 차단

- (void)getRegionalInformationFromChecked:(NSSet *)set atIndex:(NSInteger)index { 
    __block BOOL responseRecieved = NO; 
    NSString *stringForURL = [NSString stringWithFormat:@"http://www.thebluealliance.com/api/v1/event/details?event=%@",[[set allObjects] objectAtIndex:index]]; 
    NSURL *url = [NSURL URLWithString:stringForURL]; 
    NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 
    NSLog(@"URL IS GO: %@", stringForURL); 
    [NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:url] queue:queue completionHandler:^(NSURLResponse *_response, NSData *_data, NSError *_error) { 
    NSLog(@"CHECKED DATA RETURNED AT INDEX %i", index); 
    NSError *error; 
    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:_data options:NSJSONReadingMutableContainers error:&error]; 
    if (!_regionalDetails) { 
     _regionalDetails = [[NSMutableArray alloc] init]; 
    } 
    [_regionalDetails addObject:dict]; 
    responseRecieved = YES; 
}]; 
    regionalSchedulesToGet = [set count]; 
    while (responseRecieved == NO) {} 
    [[MBProgressHUD HUDForView:[[UIApplication sharedApplication] keyWindow]] setLabelText:[NSString stringWithFormat: @"Getting regional %i of %i", index+2, [set count]]]; 
    if (index+1 < [set count]) { 
     [self getRegionalInformationFromChecked:set atIndex:index+1]; 
    } else { 
     [[MBProgressHUD HUDForView:[[UIApplication sharedApplication] keyWindow]] setLabelText:@"Writing to file"]; 
    } 
} 

에서, MBProgressHUD이 값 벌금을 표시

다음은 진행 상태를 표시하는 요청 및 코드를 모두 포함하여, 호출되는 관련 코드입니다. 그러나 블록을 삽입하면 SDK는 블록을 벗어난 후에도 진행률 표시기를 업데이트하지 않습니다. 이후 스레드 문제가 해결되어야합니다. 더 이상 표시 할 요청이 없으면 "파일에 쓰는 중"이라는 메시지가 표시 될 때까지 업데이트되지 않습니다.

왜 비동기 요청이 주 스레드를 차단하는 것처럼 보이고 요청이 호출되기 전이나 후에 주 스레드에서 변경을 수행 할 수없는 이유는 무엇입니까?

+0

스레드를 차단하지 않습니다. 메인 스레드에서 UIKit을 호출하지 않기 때문에 프로그램이 UB를 호출한다는 것입니다. –

+0

흠. 나는 또한'dispatch_sync()'를 사용하여 메인 큐를 얻고 아무 쓸모없는 UI를 업데이트하려고했다. –

답변

5

을 새로 포함 모든 방법 주 스레드에서 파견하는 . 그런 다음 함수를 재귀 적으로 호출하고 다른 비동기 블록을 시작한 다음 이 완료 될 때까지 다시 블록합니다. 따라서 프로그램 제어는 모두 작업이 완료 될 때까지 메인 runloop으로 복귀하지 않습니다. 그 때만 UI 업데이트가 완료됩니다.

동기식으로 기다리는 대신 (항상 나쁜 아이디어 임) 완료 블록의 끝에서 다음 작업을 시작해야합니다. 또한 sendAsynchronousRequestqueue 인수가 방금 [NSOperationQueue mainQueue]을 사용할 수 있도록,라고 완료 핸들러를 하는 큐입니다

참고.

- (void)getRegionalInformationFromChecked:(NSSet *)set atIndex:(NSInteger)index 
{ 
    [[MBProgressHUD HUDForView:[[UIApplication sharedApplication] keyWindow]] 
    setLabelText:[NSString stringWithFormat:@"Getting regional %i of %i", index+1, [set count]]]; 
    NSString *stringForURL = [NSString stringWithFormat:@"http://www.thebluealliance.com/api/v1/event/details?event=%@",[[set allObjects] objectAtIndex:index]]; 
    NSURL *url = [NSURL URLWithString:stringForURL]; 
    NSLog(@"URL IS GO: %@", stringForURL); 
    [NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:url] queue:[NSOperationQueue mainQueue] 
          completionHandler:^(NSURLResponse *_response, NSData *_data, NSError *_error) { 
     NSLog(@"CHECKED DATA RETURNED AT INDEX %i", index); 
     NSError *error; 
     NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:_data options:NSJSONReadingMutableContainers error:&error]; 
     if (!_regionalDetails) { 
      _regionalDetails = [[NSMutableArray alloc] init]; 
     } 
     [_regionalDetails addObject:dict]; 
     if (index+1 < [set count]) { 
      [self getRegionalInformationFromChecked:set atIndex:index+1]; 
     } else { 
      [[MBProgressHUD HUDForView:[[UIApplication sharedApplication] keyWindow]] setLabelText:@"Writing to file"]; 
      // ... perhaps call a completion function from here ? 
     } 
    }]; 
} 

을하지만 참고 getRegionalInformationFromChecked에 대한 초기 호출 지금 반환 즉시 (비동기 작업이 :-) 어떻게 작동하는지 그건 :

그런 다음 코드는 대략 다음과 같습니다.

+0

고맙습니다. 간단한 질문 - 응답이 수신 될 때까지 기다리는 while 루프가 내장되어 있다면 요청이 서로 겹치지 않고 메인 스레드에서 제어되는 문제를 피할 수 없었습니까? –

+0

@ TheCraken : "while 루프가 내장되어 대기하는 중 ..."이라는 의미는 무엇입니까? *?- 그러나 어떤 경우에도 요청이 겹치지 않더라도 주 스레드에서 동 기적으로 "대기"하는 동안 UI 업데이트가 수행되지 않으므로 앱이 응답하지 않으므로 항상 피해야합니다. –

+0

잘 이해해 주셔서 감사합니다. –

-2

봅니다 UI가 비동기 블록이 완료 될 때까지 당신이 (아마도 거의 100 %의 CPU 부하) 메인 스레드를 차단

while (responseRecieved == NO) {} 

으로

+0

GCD를 사용하고 싶습니까? 나는 그것을 시도했다. 아무런 차이가 없습니다. –

관련 문제