【问题标题】:UIAlertview hanging while the thread in background is loading dataUIAlertview 在后台线程加载数据时挂起
【发布时间】:2013-02-07 06:15:44
【问题描述】:

我有一个名为“刷新数据”的 UIBarButtonItem。当用户单击它时,应用程序应刷新其数据。单击该按钮时发生的情况是启动 Web 服务并带来 xml 数据,它们的顺序为 30000-40000 条记录。所以为了防止 UI 挂起,我写了一个后台线程并在那里加载。

- (void)refreshDataAction
{
NSLog(@"Refresh Data");
//Put up an alert box indicating user to wait while data is loading.

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Data is Loading"
                                                        message:@"Please wait while data is being refreshed."
                                                       delegate:self
                                              cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil, nil];
alert.tag = 10;
[alert show];
 }

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSLog(@"hit in clickedbuttonatindex alertview at 259");
self.refreshActIndicator.hidden = NO;
[self.refreshActIndicator startAnimating];
 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
                                         (unsigned long)NULL), ^(void) {
    [self getAllCustomerValues];

    NSError *nwerror = nil;
    if (![self.secondMOC save:&nwerror])
    {
        NSLog(@"209 Failed to save second MOC");
    }
    else
    {
        //NSLog(@"saved success");
    }
 });
}

就像您可以看到警报视图一样。我单击“确定”,该框仍然“变黑”并挂在屏幕上。然后 7-8 秒后,该框消失,活动指示器开始动画。我的目标是得到这样的东西。 1.用户点击刷新数据按钮。 2.警报视图出现。 3.用户点击确定。 4.警报框消失,后台线程立即开始工作,我看到活动指示器工作/动画。

当活动指示器动画时,用户会知道要等待。那么我如何让应用程序在用户单击“确定”后立即开始动画并且警报视图确定不会变黑。我清楚了吗?如果您需要更多信息,请询问。谢谢

编辑:该屏幕在当天第一次加载时有一个后台线程在运行。在此之前有一个屏幕。在它上面我有继续按钮并点击它启动后台线程,它与这里的这个完全一样。我不会杀死它或任何东西。

编辑 2:

 - (void)refreshDataAction
   {
NSLog(@"Refresh Data");
self.txtCustomerSearch.text =@"";
[self cleanUPPreviousLabels];

//Put up an alert box indicating user to wait while data is loading.

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Data is Loading"
                                                message:@"Please wait while data is being refreshed."
                                               delegate:self
                                      cancelButtonTitle:@"OK"
                                      otherButtonTitles:nil, nil];
//alert.tag = 10;
//[alert show];
[alert performSelectorOnMainThread:@selector(show) withObject:nil waitUntilDone:FALSE];

NSLog(@"hit in willpresenet alertview at 221");
    self.refreshActIndicator.hidden = NO;
    [self.refreshActIndicator startAnimating];
NSLog(@"Dispatching");

//Disable the view and all the other controls
self.txtCustomerSearch.userInteractionEnabled =NO;
self.txtCustomerSearch.enabled =NO;
self.btnSearch.enabled =NO;
self.btnSearch.userInteractionEnabled = NO;
self.scrollView.userInteractionEnabled = NO;
//self.view.userInteractionEnabled =NO;
self.chkButton.enabled = NO;


[self deletePreviousValues]; 

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    NSLog(@"Getting customer values");
    [self getAllCustomerValues];
    NSLog(@"Got customer values");

    NSError *nwerror = nil;
    if (![self.secondMOC save:&nwerror])
    {
        NSLog(@"209 Failed to save second MOC");
    }
    else
    {
        //NSLog(@"saved success");
    }


    self.txtCustomerSearch.userInteractionEnabled = YES;
    self.txtCustomerSearch.enabled =YES;
    self.btnSearch.enabled =YES;
    self.btnSearch.userInteractionEnabled = YES;
    self.scrollView.userInteractionEnabled = YES;
    self.view.userInteractionEnabled =YES;
    self.chkButton.enabled = YES;

    [self.refreshActIndicator stopAnimating];

    NSLog(@"Saved");


});
NSLog(@"Dispatched");

}

【问题讨论】:

  • getAllCustomerValues 方法是否同步?
  • @GeorgeSachin。我怎么知道呢?
  • @GeorgeSachin - 因为它是在异步队列上执行的,所以它将异步运行。

标签: ios animation uialertview uiactivityindicatorview


【解决方案1】:

尝试改变

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
                                     (unsigned long)NULL), ^(void) {

到后台优先

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,
                                     (unsigned long)NULL), ^(void) {

【讨论】:

  • @Ric.No.更改了它,但它仍然是那样。警报框变黑并在 7-8 秒后消失,然后我的活动指示器动画开始。我还在我的原始帖子中编辑了一些信息。请检查一下。
【解决方案2】:

使用alertView:didDismissWithButtonIndex: 代替alertView:clickedButtonAtIndex:。这样,当您的代码被调用时,警报已经被解除。

问题 - 为什么要使用警报视图?用户知道他们点击了“刷新”图标。您已经显示了一个活动指示器,并且警报不会让用户有机会取消刷新。

更新:对 dispatch_async 的调用似乎有点不对劲。试试这个:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [self getAllCustomerValues];

    NSError *nwerror = nil;
    if (![self.secondMOC save:&nwerror]) {
        NSLog(@"209 Failed to save second MOC");
    } else {
        //NSLog(@"saved success");
    }
});

【讨论】:

  • 好吧,当我没有警报视图时,单击刷新按钮仍然需要 7-8 秒才能显示活动指示器。所以屏幕冻结了 7-8 秒,没有任何反应。没有指标。没有。我不知道为什么要花那个时间。但是现在我引入了警报视图,以至少告诉他们正在发生一些事情。
  • 您所描述的表明数据加载(getAllCustomerValues)确实在主线程上运行。但情况并非如此,因为您在后台队列上运行该代码。请参阅我的更新答案。
  • 我按照您的建议进行了更改。 dismissWithButtonIndex 和 dispatch_async 的变化。但也仅此而已。我点击刷新数据。警报视图打开。单击确定关闭。警报框不见了。 7-8 秒延迟(没有任何反应),然后指示器开始旋转/动画。
  • 这毫无意义。请参阅 Ric 的答案以添加一些日志记录。您应该在调用dispatch_async 中的任何日志之前看到“已调度”日志。
【解决方案3】:

添加一些 NSLog 以查看挂起的位置并停止活动指示器以查看整个挂起是否因调度而发生可能会有所帮助。

 NSLog(@"hit in clickedbuttonatindex alertview at 259");
 self.refreshActIndicator.hidden = NO;
 [self.refreshActIndicator startAnimating];
 NSLog(@"Dispatching");
 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
                                     (unsigned long)NULL), ^(void) {
    NSLog(@"Getting customer values");
    [self getAllCustomerValues];
    NSLog(@"Got customer values");

    NSError *nwerror = nil;
    if (![self.secondMOC save:&nwerror])
    {
        NSLog(@"209 Failed to save second MOC");
    }
    else
    {
        //NSLog(@"saved success");
    }
    [self.refreshActIndicator stopAnimating];
    NSLog(@"Saved");
 });
 NSLog(@"Dispatched");

发生的情况是主(UI)队列由于某种原因被停止,这导致事情看起来挂起。因为它已停止,所以即使您告诉它们开始动画,刷新活动指示器之类的东西也不会动画。请记住,您不能异步更新 UI,因此不应使用 secondMOC 导致任何表重新加载数据和 [self getAllCustomerValues];不应该做任何 UI 的事情。

【讨论】:

  • 所以在模拟器上的输出是:在 clickedbuttonatindex alertview 中点击 259.Dispatching.Getting customer values.Dispatched.Got customer values.Saved。同样在模拟器上也没有延迟(没有 7-8 秒的等待)。在设备上需要时间。
  • 在设备上调试时——“在 iOS 设备上运行”——输出是什么样的?
  • 当我将设备连接到 mac 时,在 xcode 中我得到“Phani 的 iPad、iPad 6.1 模拟器、iPhone 6.1 模拟器”。我选择“phani's ipad”然后运行,然后我在 Xcode 中看不到任何输出。你在说什么?你能解释一下吗?谢谢
  • 对不起,试试 'Debug on iOS device' 应该有输出。
  • 我使用的是ios6.1。我没有看到“在 iOS 设备上调试”选项。那在哪里?
【解决方案4】:

我们使用 MBProgressHUD (https://github.com/jdg/MBProgressHUD),这使得这种 UI 通知变得容易。通常,您提供一个可以检查 atomic BOOL 值的被调用方法。设置HUD时设置BOOL,后台进程完成后清除BOOL,HUD会自动消失。

【讨论】:

    【解决方案5】:

    你说这一切都发生在后台线程上——确保你在主线程上加载 UIAlertView:

    //[alert show];
    [alert performSelectorOnMainThread:@selector(show) withObject:nil waitUntilDone:FALSE];
    

    这可能会解决问题。您的异步调用实际上是在运行循环中的当前线程上发生的(因为它是一个后台线程),阻塞了您尝试显示的警报视图(在同一个运行循环中)。

    【讨论】:

    • 我像你说的那样编辑了我的代码。它没有用。我已经在那里发布了 refreshDataAction 修改方法。看看,如果你发现有什么不对,请告诉我。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多