2011-03-18 5 views
2

적절한 해결책을 찾기 위해 많은 조사를했지만 제대로 작동하지 않았습니다. 내 iPhone 앱이 사용자 요구에 따라 NSURL 요청을 통해 데이터를 업데이트합니다. 온라인으로로드 된 각 파일은 크기가 1.5k에 불과하지만 하나의 업데이트는 이러한 파일 중 400 개로 구성 될 수 있습니다. 그래서 나는 취소 가능한 별도의 스레드에서 다운로드 작업을 수행하고 업데이트 중에 프로세스 표시 및 취소 버튼이있는 UIAlertView가 있습니다. 그 일은 1 ... 3 분이 걸릴 수 있습니다. 따라서 장치가 살아 있거나 다른 일이 발생하는 시간 초과를 초과 할 수 있으며 앱이 백그라운드로 이동합니다.iOS의 applicationDidEnterBackground에서 작업자 스레드를 취소하는 방법

applicationDidEnterBackground이 호출 될 때 아무 것도하지 않으면 내 앱이 일시 중단되었으며 작업자 스레드도 인식됩니다. 앱이 다시 포 그라운드에있을 때 깨어나서 계속 작동합니다. 여태까지는 그런대로 잘됐다. 다시 포 그라운드에있는 후 취소 버튼을 누르면 문제가 발생합니다 - 스레드가 취소 된 상태로 반응하지만 즉시 다시 실행되고 끝에 충돌합니다 (Apple 프레임 워크의 어딘가에서 오류 코드가 있음). 응용 프로그램이 전경에 머물러있는 한 스레드를 취소하는 데 완벽하게 작동합니다. 따라서 applicationDidEnterBackground을 입력하면 중단/취소하는 것이 좋습니다. 몇 가지 시도를했지만 각 시도는 그 순간에 작업자 스레드가 일시 중단되었습니다. applicationDidEnterBackground이 호출되었으므로 스레드를 취소하고 기다릴 수 없습니다. 나는 전체 큐 물건 경험 어딘가에 같은 구조를 발견 아니에요

diagView* viewDiagCtrl = startDiag.diagViewControl; 

if (viewDiagCtrl != nil && viewDiagCtrl.actionThread != nil) 
{ 
    // UIBackgroundTaskIdentifier bgTask is instance variable 
    NSAssert(self->bgTask == UIBackgroundTaskInvalid, nil); 
    bgTask = [application beginBackgroundTaskWithExpirationHandler: 
      ^{ 
       dispatch_async(dispatch_get_main_queue(), 
       ^{ 
        NSLog(@"stopping actions definitely"); 
        [viewDiagCtrl stopBackGroundActivity:self]; 
        [application endBackgroundTask:self->bgTask]; 
        self->bgTask = UIBackgroundTaskInvalid; 
        }); 
       }]; 
    dispatch_async(dispatch_get_main_queue(), 
    ^{ 
     // Start with 10ms time boxes 
     NSTimeInterval ti = 0.01; 

     while ([application backgroundTimeRemaining] > 1.0) 
     { 
      if (![viewDiagCtrl.actionThread isExecuting]) 
       break; 

      NSDate* date = [NSDate dateWithTimeIntervalSinceNow:ti]; 

      // Let the current run-loop do it's magif for one time-box. 
      [[NSRunLoop currentRunLoop] runMode: NSRunLoopCommonModes 
         beforeDate: date]; 

      // Double the time box, for next try, max out at 1000ms. 
      ti = MIN(1.0, ti * 2); 
     } 

     [viewDiagCtrl stopBackGroundActivity:self]; 
     [application endBackgroundTask:self->bgTask]; 
     self->bgTask = UIBackgroundTaskInvalid; 
    }); 
} 

: 내가 시도 한 예는 이것이다. 모든 것들이 주 스레드에서 작동하고 작업자 스레드가 일시 중단 된 상태로 남아있어서 취소 할 기회가 없다고 가정합니다. 그와 함께 할 수있는 아이디어가 있습니까?

멀티 스레딩을하지 않고 모든 것을 시도하는 방법에 대해서도 읽었습니다.하지만 정말로 감사하지 않습니다. "배경 이동"상황을 적절하게 처리 할 수있는 유용한 링크가 있습니까?

+0

은 내가 GCD는 네트워크 프로그래밍을하는 가장 좋은 방법은 아니라고 생각. 예를 들어 사용해보십시오. 비동기 적으로 데이터를 다운로드하는 NSURLConnection 대리자 인터페이스 이렇게하면 응용 프로그램의 복잡성이 줄어들고 다중 스레드 프로그래밍의 어려움을 피할 수 있습니다. – Krumelur

+0

아직 NSURLConnection을 사용하지 않았으며 나머지는 모두 완전히 구현되었습니다. 나는 다른 길은 없을 때만이 길로 갈 것입니다. 상황은 프레젠테이션 데이터가 당분간 완전히 유효하지 않기 때문에 전체 업데이트 프로세스에 대한 사용자 I/O를 차단해야한다는 것입니다. 그래서 나는 GUI가 UIAlertView에 의한 업데이트가 필요하고 사용자 상호 작용을 잠그도록 만 허용합니다. 스레드 자체는 [[NSThread alloc] initWithTarget : selector : object :와 함께 생성되며 모든 처리가 정상적으로 작동합니다. – konran

답변

3

당신이 좋아하는 백그라운드 스레드에서 스레드의 작업을 래핑 수있는 것은 :

... 

[self performSelectorInBackground:@selector(backgroundThread) 
         withObject:nil]; 

... 


-(void)backgroundThread 
{ 
    // do a download once a minute in a background thread - dont let the system suspend us 
    while(true) 
    { 
     BOOL expire = NO;  
     bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{expire = YES;}]; 
     while(!downloadComplete && !expire) 
     { 
      //do your multiple file downloads here; 
     } 
     [[UIApplication sharedApplication] endBackgroundTask:bgTask]; 

     [NSThread sleepForTimeInterval:60]; 
    } 
} 

이것이 할 것입니다 것은 응용 프로그램이 백그라운드로하면 계속 진행중인 작업을 계속하다

- 나는이 여러 곳있다 않습니다 내 무겁게 스레드/네트워크 집중 애플 리케이션.

AFAIK : beginBackgroundTask를 호출하기 위해 앱이 백그라운드로 표시 될 때까지 기다릴 필요가 없습니다. 앱에 중단/일시 중단없이 완료해야하는 기능이 있으면 언제든지 호출해야합니다.

은 또한으로 NSURLRequest를 사용

[request setNetworkServiceType:NSURLNetworkServiceTypeVoIP]; 

(그리고 supportedbackgroundmodes 플래그에 VoIP를 배경 모드를 사용)

+0

고마워, 네,이게 실제로 있습니다.실제로 포 그라운드로 전환하는 동안 이상한 일이 발생하지만 문제를 해결할 수 있다고 생각합니다. – konran

관련 문제