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:'实际上做了什么?它可能是它所做的不是线程安全的情况(例如在后台线程中更改UI元素) – Fonix

+1

为什么你说“它不工作”?你可以发布'checkFiles'代码吗?它做了什么以及接下来会发生什么? –

+0

在'checkFiles'中添加一个日志并尝试。 –

回答

1

UI操作应该在主线程中完成。

例如:

_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

显然你是从后台线程更新UI元素。这会导致不可预知的行为。更好的方法是这样的 -

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传递给主UI线程。之后更新UI。看看这是否工作...