神秘的 UIActivityIndi​​catorView 错误?

mysterious UIActivityIndicatorView error?

当我在我的应用程序中执行特定操作时,我一直收到 EXC_BAD_ACCESS error/crash。确定这是一个内存管理问题,我启用了 NSZombies 来帮助我破译这个问题。崩溃后,我的控制台给了我以下消息:

这是我的堆栈跟踪:

以及突出显示我的应用委托行的新错误:

现在调试器指的是 UIActivityIndicatorRelease,我的堆栈跟踪中唯一突出显示的代码行是我的委托中的第一行,我的代码有问题吗Activity 指标 UI 元素?这是我的登录操作中的逻辑(每次都会强制崩溃):

@IBAction func Login(sender: AnyObject) {

        activityIND.hidden = false
        activityIND.startAnimating()

        var userName = usernameText.text
        var passWord = passwordText.text

        PFUser.logInWithUsernameInBackground(userName, password: passWord) {
            (user, error: NSError?) -> Void in
            if user != nil {

                dispatch_async(dispatch_get_main_queue()) {
                    self.performSegueWithIdentifier("loginSuccess", sender: self)
                }

            } else {
                self.activityIND.stopAnimating()

                if let message: AnyObject = error!.userInfo!["error"] {
                    self.message.text = "\(message)"
                }
            }
        }
    }

里面有没有错误?

所有绝对、肯定地操作 UI 对象的代码都必须从主线程完成。 (因此,正如@JAL 在他的评论中所说,它应该在对 dispatch_async(dispatch_get_main_queue()) 的调用中。

这不仅包括 self.activityIND.stopAnimating() 行,还包括设置标签文本的代码(任何像 UIView 一样操作 UIKit 对象的代码)。

您的 if...else 子句应如下所示:

if user != nil 
{
  dispatch_async(dispatch_get_main_queue()) 
  {
    self.activityIND.stopAnimating()
    self.performSegueWithIdentifier("loginSuccess", sender: self)
  }
}
else 
{
  dispatch_async(dispatch_get_main_queue()) 
  {
    self.activityIND.stopAnimating()
    if let message: AnyObject = error!.userInfo!["error"] 
    {
      self.message.text = "\(message)"
    }
  }
}

事实证明,在我的 viewDidLoad() 中,我有以下代码试图隐藏负载上的指示器:

UIActivityIndicator.appearance().hidden = true UIActivityIndicatorView.appearance().hidesWhenStopped = true

不知道这会为应用程序的其余部分取消分配指示器,所以当我在登录逻辑中调用以下内容时:

activityIND.hidden = false

activityIND.startAnimating()

我正在向不再可用的实例发送消息,导致崩溃。所以我所做的就是在 viewDidLoad() 中调整我的代码 至:

activityIND.hidden = true

activityIND.hidesWhenStopped = true

使用我创建的特定插座的名称而不是通用名称 UIActivityIndicatorView

所有 UI 相关操作应在主线程中执行,即在

dispatch_async(dispatch_get_main_queue(){}

阻止

@IBAction func Login(sender: AnyObject) {

        activityIND.hidden = false
        activityIND.startAnimating()

        var userName = usernameText.text
        var passWord = passwordText.text

        PFUser.logInWithUsernameInBackground(userName, password: passWord) {
            (user, error: NSError?) -> Void in
            if user != nil {

                dispatch_async(dispatch_get_main_queue()) {
                    self.performSegueWithIdentifier("loginSuccess", sender: self) //UI task
                }

            } 
            else {
                dispatch_async(dispatch_get_main_queue()) 
               {
                 self.activityIND.stopAnimating() //UI task
                 if let message: AnyObject = error!.userInfo!["error"] 
                 {
                   self.message.text = "\(message)" //UI task
                  }
                 };
            }
        }
    }

参考一些关于并发的好文章here and here