在我的模态用户界面中,有一个" 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。请帮帮我。
答案 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,然后考虑上传失败时您要做什么 - 这可能很容易在很长一段时间后发生。