dismissViewControllerAnimated:completion: 有几秒的延迟。

16

我的应用程序中dismissViewControllerAnimated:completion:工作正常,除了消失之间的延迟。

[api loginWithUsername:[dict objectForKey:@"username"] andPassword:[dict objectForKey:@"password"] andSuccessBlock:^(id json) {
    NSLog(@"DONE... %@", [json objectForKey:@"status"]);
    NSString *status = [json objectForKey:@"status"];
    if([status isEqualToString:@"ok"]){
        app.user = [json objectForKey:@"data"];
        [self dismissViewControllerAnimated:YES completion:nil];
    }else{
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"could not log you in" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
        [alert show];
    }
}];

在我的控制台中,我可以看到打印出了“DONE... ok”,这意味着回调块已经执行,但大约3-4秒后模态视图才最终被关闭。

是什么原因导致了这种延迟?


使用Instruments的时间分析器来查看哪些操作耗费了最多的时间。 - Mario
3个回答

35

如果您不能保证UI代码在主线程上运行,它可能会在其他线程上运行,在这种情况下,您将经历几秒钟的延迟!

您可以添加以下内容以确保dismissal在主线程上运行:

dispatch_async(dispatch_get_main_queue(), ^{
    [self dismissViewControllerAnimated:YES completion:nil];
});

通常情况下,这不是问题,因为大多数代码已经在主线程上运行,因为我们大多数添加的代码都是从UIKit方法(例如viewDidLoad等)运行的。这些方法保证在主线程上运行。

当您在另一个线程上运行代码时,问题就出现了。一个例子是,在完成块调用网络库时,请求在后台完成。


2
这正是问题所在。 - Chadams
请问我为什么需要这个?我有一个简单的PresentedViewcontroller。在某个时候,我执行了以下代码:[self dismissViewControllerAnimated:YES completion:^{ [self.delegate funcDidSelected]; }];当我dismiss presentedViewController时,它需要5秒钟才能执行完毕。我的presentingViewController除了拥有一个简单的UITableView之外,并没有做复杂的事情。 - felixwcf
1
@Felix 因为解散和呈现视图控制器是 UI 操作。所有的 UI 操作都必须在应用程序的主线程上运行。如果您在任何其他线程上运行此类操作,通常会出现大的延迟,甚至可能没有效果。大多数代码已经在主线程上运行,因此通常不需要担心这个问题,但在某些情况下需要注意。 - manecosta
@manecosta 是的,在我的 presentingViewController 中有一个委托函数,当它从 presentedViewController 被调用时,它将在解除 presentedViewController 后执行 push viewcontroller。正如你上面所说的,我猜它可能已经影响了主线程中的代码执行。非常感谢你,我学到了新的东西,并更好地理解了主线程的执行。 - felixwcf
manecosta的解决方案解决了我的问题。由于某种原因,我的模态视图控制器关闭时有明显的延迟(长达2,3秒)。我在Swift 2.1.1中使用了以下语法来解决延迟问题。注意:picker是传递给其委托的视图控制器对象之一。委托的任务之一是关闭选择器视图控制器:dispatch_async(dispatch_get_main_queue()) { picker.dismissViewControllerAnimated(true, completion: nil) } - Jervisbay

3

请检查ParentViewController的'viewWillAppear'和当前视图控制器的'viewWillDisappear'函数。确保这两个函数中没有任何繁重的计算和内存分配。


0

尝试更改

NSString *status = [json objectForKey:@"status"];
NSLog(@"DONE... %@", status);

然后尝试

if([status isEqualToString:@"ok"]){

    [self dismissViewControllerAnimated:YES completion:nil];
    app.user = [json objectForKey:@"data"];
}else{

由于我不知道你的JSON对象有多大,它可能需要一些时间来响应。由于您在日志语句之后再次调用它,并且在说“dismiss”之前执行了其他操作,因此可能会出现这种情况。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接