我有一个视图控制器,显示在我的应用程序的开头,以准备我正在使用Core Data的UIManagedDocument。问题:当我在带有iOS 7.1的iPhone 4S设备上运行应用程序时,我一直遇到swift_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
感觉不对。如果有帮助,这里是Debug Navigator中的完整日志:
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
答案 0 :(得分:7)
这里的问题是无主参考。当自我被释放时,该块仍然保留自我,因此试图调用自己是零。使用弱以防止这种情况。由于weak是块内的可选类型,因此可以使用条件展开并执行其他代码,
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()
}
}
}
}
}
答案 1 :(得分:1)
我不认为保留周期可能存在问题。 prepareWithCompletionHandler
闭包参数捕获self
,但self
(SetupViewController
的实例)不拥有文档变量。在这种情况下,您不需要使用捕获列表。