【问题标题】:UIAlertController sometimes prevents UIRefreshControl to hideUIAlertController 有时会阻止 UIRefreshControl 隐藏
【发布时间】:2017-01-08 15:33:51
【问题描述】:

我在我的 tableview 上使用UIRefreshControl 来更新项目。最后,我显示一个UIAlertController 来通知用户更新已完成,以及更新了多少项目。非常简单,它适用于一件事。如果我连续多次拉动刷新,有时刷新控件不会被解除,即使在解除警报之后也是如此。我需要向上滑动桌子才能让它消失。

这是我使用的代码,所有 UI 的东西都在主线程上很好地完成了:

    if(refreshControl.refreshing) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [self refreshItems];

            dispatch_async(dispatch_get_main_queue(), ^{
                [refreshControl endRefreshing];
                [self.tableView reload];
                [self showUpdateInfo];                     
            });
        });
    }

知道是什么原因造成的吗?

编辑:这就是我在代码中创建刷新控件的方式(viewDidLoad):

UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
refreshControl.attributedTitle   = [[NSAttributedString alloc] initWithString: @"Checking for updates…"];
[refreshControl addTarget: self
                   action: @selector(refreshOutdatedItems)
         forControlEvents: UIControlEventValueChanged];

self.refreshControl = refreshControl;

【问题讨论】:

  • 您是在代码中创建 UIRefreshControl 还是使用 TableViewController 属性?
  • 查看我的问题中的编辑。
  • 我试图重现该问题。您的代码似乎按预期工作。顺便说一句,您的 dispach_sync 实际上让我崩溃了。这是故意的还是应该是 dispatch_async ?
  • 这是一个错字,已修复。
  • 我能够在模拟器中重现该问题。如果我快速刷新表格两次 UIAlertController 显示但 tableview 永远不会恢复并卡在中间并且它显示 refreshcontroller 仍在旋转。我猜 tableview 在显示警报控制器时没有足够的时间向上滚动并冻结。可能需要设置一些小计时器才能让 tableview 有机会备份。

标签: ios objective-c uialertcontroller uirefreshcontrol


【解决方案1】:

延迟任意时间不是一个非常干净的解决方案。在我看来,通过将双倍数增加到 1000 万来实现延迟也有点像 hack。

我最终所做的与这个伪 Swift 类似:

let alert = UIAlertController(...)
present(alert, animated: true) {
    refreshControl.endRefreshing()
}

它会延迟对 endRefreshing() 的调用,直到出现警报。

我使用 Swift 3 和 PromiseKit 的实际代码看起来更像这样:

@IBAction func onRefresh() {
    Repository.getNewData().then { data in
        self.data = data
        self.tableView.reloadData()
    }.recover { error in
        // Return a promise to make sure endRefreshing isn't called until the alert is presented.
        return self.presentErrorAlert(message: "Some user-friendly message")
    }.always {
        self.refreshControl?.endRefreshing()
    }
}

private func presentErrorAlert(message: String) -> Promise<Void> {
    return Promise<Void> { fulfill, _ in
        let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
        self.present(alert, animated: true) {
            fulfill()
        }
    }
}

【讨论】:

  • 这应该是公认的答案——任意延迟是一种黑客行为。
  • 请在没有响应式代码的情况下用 Objective C 重写答案,所以我可以试试这个。
【解决方案2】:

这些对我有用:

    refreshControl.endRefreshing()
    tableView.setContentOffset(CGPoint.zero, animated: true)
    -- show alert than --

【讨论】:

  • 这似乎是一个肮脏的 hack,但比其他解决方案效果更好,因为警报视图控制器不一定需要从刷新本身触发,但可能来自另一个异步操作
【解决方案3】:

只需重置表格视图的内容偏移量:

- (void)endRefreshControl {
     [self.tableView setContentOffset:CGPointMake(0, -self.refreshControl.bounds.size.height) animated:YES];
     [self.refreshControl endRefreshing];
}

您的任务完成后,请致电[self endRefreshControl];
而不是[self.refreshControl endRefreshing];

【讨论】:

    【解决方案4】:

    这似乎是 Xcode 中的一个错误。甚至 Johan Levin 的解决方案有时也似乎挂在 Xcode 9.2 中。

    这不是您要寻找的,但它是一种解决方法:不要使用 UIAlertController。只需将您在 UIAlertController 中的文本放入 UIRefreshControl 中,如下所示:

    refreshControl?.attributedTitle = NSAttributedString(string: "Pull to reload all reminders", attributes: [NSAttributedStringKey.foregroundColor: UIColor(red: 255.0/255.0, green: 182.0/255.0, blue: 8.0/255.0, alpha: 1.0)])
    

    【讨论】:

      【解决方案5】:

      将此扩展添加到您的视图控制器:

      extension UIViewController {
          func showAlert(withTitle title: String, andMessage message: String, completion: (() -> Void)? = nil) {
              let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
              alert.addAction(UIAlertAction(title: L10n.General.ok, style: .default, handler: { _ in
                  self.dismiss(animated: true, completion: nil)
              }))
              self.present(alert, animated: true, completion: completion)
          }
      }
      

      然后使用以下代码显示警报。在警报的完成块中,刷新控件停止并平滑淡出。

      showAlert(withTitle: "My Title", andMessage: "There was an error", completion: { 
            refreshControl.endRefreshing() 
       })
      

      【讨论】:

        【解决方案6】:

        我相信这确实与 tableView 在 UIAlertController 出现之前没有向上滚动有关。我尝试为 showUpdateInfo 方法设置延迟,这似乎有效。我猜当用户只拉一次时,需要半秒钟来显示 UIAlertController 检查是否有帮助。 这是我的代码

        - (void)refreshOutdatedItems
        {
            NSLog(@"refresh");
        
            if (self.refreshControl.refreshing) {
                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                    for (double i = 0 ; i < 100000000; i++){
        
                    };
        
                    dispatch_async(dispatch_get_main_queue(), ^{
        
                        [self.refreshControl endRefreshing];
                        [self performSelector:@selector(showUpdateInfo) withObject:nil afterDelay:0.5];
        
                    });
                });
            }
        }
        

        如果有帮助请告诉我。

        【讨论】:

        • 太棒了!它的工作更顺畅(在我看来),延迟更短(0.1 秒)。
        • 我在 0.5 秒时放回去,在 0.1 秒时它仍然会发生。
        • 我猜这取决于数据刷新完成时表视图的位置。也许有一种方法可以检测 tableview 何时结束动画,但可能有点复杂。
        • 我现在对它很满意,所以我会在 0.5 秒 :)
        • 太棒了!编码愉快!
        猜你喜欢
        • 2013-10-29
        • 1970-01-01
        • 1970-01-01
        • 2016-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多