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か?

4

2 に答える 2

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?
});

そのような可能性のあるすべてのケースを変更します。

于 2013-06-20T10:25:17.953 に答える
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 を更新します。これが機能するかどうかを確認してください...

于 2013-06-20T10:32:09.323 に答える