即使使用GCD,UI仍然延迟

时间:2014-08-20 05:08:13

标签: ios objective-c grand-central-dispatch

在我的模态用户界面中,有一个" DONE"与IBAction -done:链接的按钮,它会将文本上传到(比方说Dropbox服务器)。它的代码看起来像这样

- (IBAction)done:(id)sender {
// must contain text in textview
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
if (![_textView.text isEqualToString:@""]) {

    // check to see if we are adding a new note
    if (!self.note) {
        DBFile *newNote = [[DBFile alloc] init];
        newNote.root = @"dropbox";
        self.note = newNote;
    }

    _note.contents = _textView.text;
    _note.path = _filename.text;

    // - UPLOAD FILE TO DROPBOX - //
    NSLog(@"Initializing URL...");
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
        NSURL *url = [Dropbox uploadURLForPath:self.note.path];
        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
        [request setHTTPMethod:@"PUT"];
        NSData *noteContents = [self.note.contents dataUsingEncoding:NSUTF8StringEncoding];
        NSLog(@"Creating session task...");
        NSURLSessionUploadTask *uploadTask = [self.session uploadTaskWithRequest:request
                                                                        fromData:noteContents
                                                               completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                                   NSHTTPURLResponse *resp = (NSHTTPURLResponse *) response;
                                                                   if (!error && resp.statusCode == 200) {
                                                                       NSLog(@"OK");
                                                                       dispatch_async(dispatch_get_main_queue(), ^{
                                                                           [self.delegate noteDetailsViewControllerDoneWithDetails:self];
                                                                       });
                                                                   } else {
                                                                       NSLog(@"Status code: %d", resp.statusCode);
                                                                   }
                                                               }];
        [uploadTask resume];
    });
} else {
    UIAlertView *noTextAlert = [[UIAlertView alloc] initWithTitle:@"No text"
                                                          message:@"Need to enter text"
                                                         delegate:nil
                                                cancelButtonTitle:@"Ok"
                                                otherButtonTitles:nil];
    [noTextAlert show];
}

}

委托方法noteDetailsViewControllerDoneWithDetails:这个类看起来像这样

-(void)noteDetailsViewControllerDoneWithDetails:(NoteDetailsViewController *)controller{
// refresh to get latest
[self dismissViewControllerAnimated:YES completion:nil];
[self notesOnDropbox];}

(notesOnDropbox是一项耗时的任务)。当点击DONE按钮时,我希望这个模态VC / UI立即解除并在背景上获取数据(通过notesOnDropbox方法)。但是,当我尝试点击DONE按钮时,我的UI停止响应大约几秒钟,之后模式UI被解除。我无法弄清楚我在哪里滥用GCD。请帮帮我。

3 个答案:

答案 0 :(得分:1)

首先,如果notesOnDropbox是一项耗时的任务,那么你不应该在主线程上执行它(正如你所做的那样)。如果它足够耗时并且您在主线程上执行它,那么WatchDog进程将在用户眼前杀死您的应用程序。

其次,没有必要离开主线程来进行上传。如果正确使用NSURLSession,它将是异步的。

答案 1 :(得分:1)

如果你想立即解雇你的模态VC / UI,只要让代表解雇,

喜欢是:

 - (IBAction)done:(id)sender {
      [self.delegate noteDetailsViewControllerDoneWithDetails:self];
      // ...
 }

在示例代码中

在上传任务完成后执行解除操作,但上传任务是异步的。

你要求代表解雇使用GCD dispatch_async,这也是异步任务。

毕竟,您必须考虑上传时间,上传任务的人员以及调用notesOnDropbox的时间。

答案 2 :(得分:0)

您的代码仅在整个上传任务完成时调用noteDetailsViewControllerDoneWithDetails,因为这是您编写代码的方式。实际上,情况似乎更糟。如果上传任务有任何问题,则永远不会调用noteDetailsViewControllerDoneWithDetails。

您需要尽快调用noteDetailsViewControllerDoneWithDetails,然后考虑上传失败时您要做什么 - 这可能很容易在很长一段时间后发生。