0

Я пытаюсь улучшить отзывчивость моего приложения, но я полный новичок для потоковой передачи и запутался.Фоновая нить путаницы

На старте предупреждение показано:

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex 
{ 
    if (buttonIndex == 0) 
    { 
     NSString *user = [[alertView textFieldAtIndex:0] text]; 
     NSString *pass = [[alertView textFieldAtIndex:1] text]; 
     [self loginToServerWithUsername:user andPassword:pass]; 
    } 
} 

в методе loginToServerWithUsername:, приложение вызывает метод:

[self checkFiles:sessionID]; 

Это может занять несколько секунд, так что я пытался выполнить его в фоновом режиме метод

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
         [self checkFiles:sessionID]; 
        }); 

checkFiles:

fileList = [[NSMutableString alloc] init]; 

NSArray *directoryPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
NSString *documentsDirectory = [directoryPaths objectAtIndex:0]; 
NSString *downloadsFolderString = [documentsDirectory stringByAppendingPathComponent:DOWNLOADS_FOLDER]; 
NSError *error = nil; 
NSString* file; 
NSDirectoryEnumerator* enumerator = [[NSFileManager defaultManager] enumeratorAtPath:downloadsFolderString]; 
while (file = [enumerator nextObject]) 
{ 
    BOOL isDirectory = NO;   
    [[NSFileManager defaultManager] fileExistsAtPath: [NSString stringWithFormat:@"%@/%@",downloadsFolderString,file] 
             isDirectory: &isDirectory]; 

      if (!isDirectory) 
      { 
       [fileList appendString:[NSString stringWithFormat:@"%@|", file]]; 
      } 
} 
NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 
[formatter setDateFormat:@"dd/MM/yyyy HH:mm"]; 
NSString *timeOpened = [formatter stringFromDate:[NSDate date]]; 

NSString *post = [NSString stringWithFormat:@"sessionID=%@&fileList=%@&dateTime=%@&userID=%@", sessionID, fileList, timeOpened, userID]; 
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; 
NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]]; 
NSString *comparisonURLString = SERVER_COMPARE_URL_STRING; 
NSURL *comparisonURL = [NSURL URLWithString:comparisonURLString]; 
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:comparisonURL]; 
[request setHTTPMethod:@"POST"]; 
[request addValue:postLength forHTTPHeaderField:@"Content-Length"]; 
[request setHTTPBody:postData]; 
NSHTTPURLResponse *urlResponse = nil; 
error = nil; 
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&error]; 

if (responseData) 
{ 
    NSString *requiredFilesList = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]; 

    NSArray *lines = [requiredFilesList componentsSeparatedByString: @"\n"];   
    if (lines.count > 2) 
    { 
     dispatch_async(dispatch_get_main_queue(), ^(void){ 

      NSRange theRange; 
      theRange.location = 2; 
      theRange.length = [lines count] -3; 
      numberOfFilesToBeDownloaded = theRange.length; 

      if (numberOfFilesToBeDownloaded <= 0) 
      { 
       _jobStatusLabel.text = @"Documents up to date"; // is this the issue? 
      }    
      if (numberOfFilesToBeDownloaded > 0) 
      { 
       NSArray *subArray = [lines subarrayWithRange:theRange]; 
       [self animateProgressBar]; 
       if (![eraseDevice isEqualToString:@"true"]) 
       { 
       [self getFiles:subArray]; 
       } 
      } 
     }); 
    } 
} 
else 
{ 
    NSLog(@"no response data from check files"); 
} 

Однако alertView не отвергались, пока метод checkFiles не будет завершена. Может ли кто-нибудь сказать мне, как убрать предупреждение, пока checkFiles работает в фоновом режиме?

+0

Что делает 'checkFiles:' на самом деле? это может быть случай, когда его выполнение не является потокобезопасным (например, изменение элементов пользовательского интерфейса в фоновом потоке) – Fonix

+1

Почему вы говорите «это не сработало»? можете ли вы отправить код 'checkFiles'? что он делает и что должно произойти дальше? –

+0

добавьте журнал в 'checkFiles' и попробуйте. –

ответ

1

Операции пользовательского интерфейса должны выполняться в основном потоке.

Например:

_jobStatusLabel.text = @"Documents up to date"; // is this the issue? 

должен быть

dispatch_async(dispatch_get_main_queue(), ^(void){ 
    _jobStatusLabel.text = @"Documents up to date"; // is this the issue? 
}); 

Измените все такие возможные случаи.

+0

Спасибо, я попробую. – Robert

+0

После немного возиться, я добиваюсь прогресса. Спасибо за вашу помощь. – Robert

1

Очевидно, что вы обновляете элементы пользовательского интерфейса из фоновой темы. Это приведет к непредсказуемому поведению. Лучший способ сделать это - вот так:

dispatch_queue_t queue = dispatch_get_global_queue(0, 0); 
dispatch_async(queue, ^{ 
    [self checkFiles:sessionID]; 

    dispatch_async(dispatch_get_main_queue(),^{ 
     //breakup your checkFiles method to background tasks & UI tasks. Put UI updating 
     //code here which will get executed in the main thread. 
    }); 
}); 

Это шаблон кодирования GCD. Здесь асинхронный поток выполняет синхронный код. т. е. после того, как checkFiles завершит выполнение следующего кода (здесь его асинхронный поток).

Вам нужно будет переломить checkFiles метод. Выполните HTTP-часть в фоновом потоке и передайте разобранный responseData в основной поток пользовательского интерфейса. После этого обновите пользовательский интерфейс. Посмотрите, работает ли это ...