NSNotificationCenter 导致 SpriteKit 出现 EXC_BAD_ACCESS 错误
NSNotificationCenter causing EXC_BAD_ACCESS error with SpriteKit
我正在使用 NSNotificationCenter 试图控制 SpriteKit 中的计时器。当我第一次进入 SKScene 时,代码运行良好,但当我尝试重新进入 SKScene 时,出现 EXC_BAD_ACCESS 错误。我认为这与 removeObserver 函数有关。我不确定何时删除观察者,我尝试在 prepareForSegue 函数中执行此操作但没有成功。我的viewController如下:
class JobStartedViewController: UIViewController {
var titleOfJob: String = ""
override func viewDidLoad() {
super.viewDidLoad()
let skView = self.view as! SKView
let scene:SKScene = GameScene.init(size: skView.bounds.size)
NSNotificationCenter.defaultCenter().postNotificationName("stopTimerNotification", object: nil)
NSNotificationCenter.defaultCenter().postNotificationName("startTimerNotification", object: nil)
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
然后我将我的观察者添加到我的 GameScene.swift 中,如下所示:
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "stopTimerInBackground:", name:"stopTimerNotification", object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "startTimerInBackground:", name:"startTimerNotification", object: nil)
以下是可能的事件流程:
- 您呈现
JobStartedViewController
,它创建场景并将其添加到视图,触发 didMoveToView(_:)
并添加两个观察者。
- 您关闭视图控制器或从
SKView
中删除场景。不久之后的某个时候,场景不再有强引用,它就会被释放。 此时通知中心仍然存在对它的不安全引用
- 您提交另一个
JobStartedViewController
或 post stopTimerNotification
通知。
NSNotificationCenter
尝试在取消分配的场景上执行选择器并使您的应用程序崩溃。
使用 NSNotificationCenter
时的正常做法是在 Objective-C 的 dealloc
方法或 Swift 的 deinit
方法中删除观察者:
class GameScene: SKScene {
// ...
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
}
如果您打算多次在视图中添加和删除该场景,您还应该考虑在 willMoveFromView(_:)
中删除观察者。
我正在使用 NSNotificationCenter 试图控制 SpriteKit 中的计时器。当我第一次进入 SKScene 时,代码运行良好,但当我尝试重新进入 SKScene 时,出现 EXC_BAD_ACCESS 错误。我认为这与 removeObserver 函数有关。我不确定何时删除观察者,我尝试在 prepareForSegue 函数中执行此操作但没有成功。我的viewController如下:
class JobStartedViewController: UIViewController {
var titleOfJob: String = ""
override func viewDidLoad() {
super.viewDidLoad()
let skView = self.view as! SKView
let scene:SKScene = GameScene.init(size: skView.bounds.size)
NSNotificationCenter.defaultCenter().postNotificationName("stopTimerNotification", object: nil)
NSNotificationCenter.defaultCenter().postNotificationName("startTimerNotification", object: nil)
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
然后我将我的观察者添加到我的 GameScene.swift 中,如下所示:
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "stopTimerInBackground:", name:"stopTimerNotification", object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "startTimerInBackground:", name:"startTimerNotification", object: nil)
以下是可能的事件流程:
- 您呈现
JobStartedViewController
,它创建场景并将其添加到视图,触发didMoveToView(_:)
并添加两个观察者。 - 您关闭视图控制器或从
SKView
中删除场景。不久之后的某个时候,场景不再有强引用,它就会被释放。 此时通知中心仍然存在对它的不安全引用 - 您提交另一个
JobStartedViewController
或 poststopTimerNotification
通知。 NSNotificationCenter
尝试在取消分配的场景上执行选择器并使您的应用程序崩溃。
使用 NSNotificationCenter
时的正常做法是在 Objective-C 的 dealloc
方法或 Swift 的 deinit
方法中删除观察者:
class GameScene: SKScene {
// ...
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
}
如果您打算多次在视图中添加和删除该场景,您还应该考虑在 willMoveFromView(_:)
中删除观察者。