Ios 在一个可能的块/闭包保留周期中获得一个swift_unknowneakrelease()

Ios 在一个可能的块/闭包保留周期中获得一个swift_unknowneakrelease(),ios,iphone,cocoa-touch,swift,automatic-ref-counting,Ios,Iphone,Cocoa Touch,Swift,Automatic Ref Counting,我有一个视图控制器,它显示在我的应用程序的开头,用于准备我正在使用的用于核心数据的UIManagedDocument。问题:当我在装有iOS 7.1的iPhone 4S设备上运行应用程序时,我总是遇到一个swift\u unknownWeakRelease()崩溃。代码如下: class SetupViewController: UIViewController { @IBOutlet weak var loadingView: UIActivityIndicatorView!

我有一个视图控制器,它显示在我的应用程序的开头,用于准备我正在使用的用于核心数据的UIManagedDocument。问题:当我在装有iOS 7.1的iPhone 4S设备上运行应用程序时,我总是遇到一个
swift\u unknownWeakRelease()
崩溃。代码如下:

class SetupViewController: UIViewController {

    @IBOutlet weak var loadingView: UIActivityIndicatorView!

    override func viewDidAppear(animated: Bool)  {
        super.viewDidAppear(animated)
        let document = SPRManagedDocument.sharedDocument()

        document.prepareWithCompletionHandler {[unowned self] success in
            if success {
                self.dismissViewControllerAnimated(false, completion: nil)
            } else {
                self.loadingView.stopAnimating()
                UIAlertView(title: "Error", message: "Categories can't be loaded.", delegate: nil, cancelButtonTitle: "OK").show()
            }
        }
    }

}

我怀疑在块和
self
之间有一个很强的参考循环,因为这是我唯一能看到它可能发生的地方。没错,如果我将捕获列表从
[unowned self]
更改为
[weak self]
,或者将其全部删除(在闭包中保留对
self
的强引用),程序将继续正常运行当我在带iOS 8的iPhone 5模拟器或带iOS 7.1的5S模拟器上运行应用程序时,不会发生此错误。

我如何以不同的方式编写代码,以便在所有运行iOS 7.0+的设备上避免崩溃?我确信
unowned
是正确的修饰语。我希望
self
仍然存在,直到
completionHandler
完成,所以
weak
感觉不对劲。以下是调试导航器中的完整日志(如果有帮助):

Thread 1Queue : com.apple.main-thread (serial)
#0  0x0050c0ae in swift_unknownWeakRelease ()
#1  0x0012d760 in Spare.SetupViewController.(viewDidAppear (Spare.SetupViewController) -> (Swift.Bool) -> ()).(closure #1) at /Users/local.m.quiros/Development/spare-ios/Spare/View Controllers/SetupViewController.swift:28
#2  0x00108a8c in reabstraction thunk helper from @callee_owned (@unowned Swift.Bool) -> (@unowned ()) to @callee_owned (@in Swift.Bool) -> (@out ()) at /Users/local.m.quiros/Development/spare-ios/Spare/View Controllers/EditCategoryViewController.swift:180
#3  0x0012c68c in partial apply forwarder for reabstraction thunk helper from @callee_owned (@unowned Swift.Bool) -> (@unowned ()) to @callee_owned (@in Swift.Bool) -> (@out ()) ()
#4  0x00108ac4 in reabstraction thunk helper from @callee_owned (@in Swift.Bool) -> (@out ()) to @callee_owned (@unowned Swift.Bool) -> (@unowned ()) at /Users/local.m.quiros/Development/spare-ios/Spare/View Controllers/EditCategoryViewController.swift:180
#5  0x00108b18 in reabstraction thunk helper from @callee_owned (@unowned Swift.Bool) -> (@unowned ()) to @callee_unowned @objc_block (@unowned ObjectiveC.ObjCBool) -> (@unowned ()) at /Users/local.m.quiros/Development/spare-ios/Spare/View Controllers/EditCategoryViewController.swift:180
#6  0x00149e68 in __51-[SPRManagedDocument prepareWithCompletionHandler:]_block_invoke at /Users/local.m.quiros/Development/spare-ios/Spare/Objects/SPRManagedDocument.m:49
#7  0x3b4baf86 in _dispatch_barrier_sync_f_slow_invoke ()
#8  0x3b4b381e in _dispatch_client_callout ()
#9  0x3b4ba49e in _dispatch_main_queue_callback_4CF$VARIANT$mp ()
#10 0x3071b8a0 in __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ ()
#11 0x3071a174 in __CFRunLoopRun ()
#12 0x30684ebe in CFRunLoopRunSpecific ()
#13 0x30684ca2 in CFRunLoopRunInMode ()
#14 0x355de662 in GSEventRunModal ()
#15 0x32fd114c in UIApplicationMain ()
#16 0x00167060 in main at /Users/local.m.quiros/Development/spare-ios/Spare/main.m:16

我不认为这个周期会有问题
prepareWithCompletionHandler
closure参数捕获
self
,但
self
SetupViewController
的实例)不拥有文档变量。在这种情况下,您不需要使用捕获列表。

这里的问题是无主引用。释放self时,块仍保留self,因此尝试调用为nil的self。使用“弱”以防止出现这种情况。由于“弱”是块内的可选类型,所以可以使用条件展开并执行其他代码,如下所示:

class SetupViewController: UIViewController {

  @IBOutlet weak var loadingView: UIActivityIndicatorView!

  override func viewDidAppear(animated: Bool)  {
    super.viewDidAppear(animated)
    let document = SPRManagedDocument.sharedDocument()

    document.prepareWithCompletionHandler {[weak self] success in
      if let weakSelf = self{
        if success {
          weakSelf.dismissViewControllerAnimated(false, completion: nil)
        } else {
          weakSelf.loadingView.stopAnimating()
          UIAlertView(title: "Error", message: "Categories can't be loaded.", delegate: nil, cancelButtonTitle: "OK").show()
        }
      }
    }
  }

}

“如果我将捕获列表从[无主自我]更改为[弱自我]”,那么您如何处理
self
是可选的?您是否将使用
self
替换为
self,还是你做了别的事?嗯。。。关门怎么样?谁拥有完成处理程序?闭包由
prepareWithCompletionHandler
参数变量拥有,并保留到
prepareWithCompletionHandler
返回。如果在闭包执行结束之前不想保留self,可以使用@insane-36方法,但这里没有保留周期的风险。我还遇到了swift_未知的弱发布崩溃问题。将“无主自我”替换为“弱自我”,并通过零检查将其修复。谢谢!回答得很好。我想添加一些链接,帮助我更好地理解它:(苹果的东西)和(一些酷家伙)。