我正在尝试使用 KVO 来观察在我的页面 View Controller 的子内容 View Controller 的 ScrollView 中使用拖动时的更新变化,但是当应用程序启动时,它崩溃了说:
“由于未捕获的异常‘NSInternalInconsistencyException’而终止应用程序,原因:‘类 KVOPageVC.ContentViewController 的实例 0x7ff003d3f5b0 已被释放,而键值观察者仍在其中注册。”
下面是我的代码和截图:
代码
PageViewController.swift
import UIKit
class PageViewController: UIPageViewController {
var pageLabels: Array<String> = ["First Page", "Second Page", "Third Page"]
override func viewDidLoad() {
super.viewDidLoad()
dataSource = self
self.setViewControllers([contentViewForPage(0)], direction: .Forward, animated: true, completion: nil)
}
func contentViewForPage(index: Int) -> ContentViewController {
let contentVC = storyboard!.instantiateViewControllerWithIdentifier("ContentVC") as! ContentViewController
contentVC.pageIndex = index
contentVC.label = pageLabels[index]
return contentVC
}
}
extension PageViewController: UIPageViewControllerDataSource {
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
let vc = viewController as! ContentViewController
var index = vc.pageIndex as Int
if index == 0 || index == NSNotFound {
return nil
}
index -= 1
return contentViewForPage(index)
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
let vc = viewController as! ContentViewController
var index = vc.pageIndex as Int
if index == NSNotFound {
return nil
}
index += 1
if index == self.pageLabels.count {
return nil
}
return contentViewForPage(index)
}
}
ObeserverViewController.swift
它是嵌入在“内容 View Controller ”的“容器 View ”中的“ View Controller ”,当用户拖动并释放下面的滚动条时,我希望表情符号面被替换为“通知! "
import UIKit
class ObeserverViewController: UIViewController {
@IBOutlet weak var notifyLabel: UILabel!// when the user drag the scroll view and release, i hope its value will be changed accordingly.
var contentVC: ContentViewController! //the variable to hold the object
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.contentVC = self.storyboard!.instantiateViewControllerWithIdentifier("ContentVC")
self.contentVC.addObserver(self, forKeyPath: "changingLabel", options: [], context: nil)
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
self.contentVC.removeObserver(self, forKeyPath: "changingLabel")
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if keyPath == "changingLabel" {
notifyLabel.text = "to be notified!"
}
}
deinit {
self.contentVC.removeObserver(self, forKeyPath: "changingLabel")
}
}
ContentViewController.swift
页面 View Controller 的 subview Controller ,共3页。它包括一个 ScrollView 和一个容器 View (嵌入式 ObeserverViewController)
import UIKit
class ContentViewController: UIViewController {
var label: String!
var pageIndex: Int!
dynamic var changingLabel: String = ""
@IBOutlet weak var contentLabel: UILabel!
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var contentView: UIView!
@IBOutlet weak var containerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
contentLabel.text = label
self.scrollView.delegate = self
self.contentView.backgroundColor = UIColor.greenColor()
}
}
extension ContentViewController: UIScrollViewDelegate {
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if scrollView.contentOffset.y < -50 {
if contentView.backgroundColor == UIColor.greenColor() {
contentView.backgroundColor = UIColor.yellowColor()
self.setValue("hah", forKey: "changingLabel")
} else {
contentView.backgroundColor = UIColor.greenColor()
self.setValue("wow", forKey: "changingLabel")
}
}
}
}
My questions is:
当我在另一个 Controller 中拖动和释放 ScrollView 时,如何让表情符号标签文本在一个 Controller 中被通知更改?
非常感谢您!
最佳答案
首先,您要将观察者添加到一个对象并从另一个对象中移除。当您调用 instanciateViewController...
时,它将为您创建传递的 View Controller 标识符的新对象。比您通过 KVO 签署它的更改。但是在 viewWillDissapear
中,您得到的不是在 viewWillAppear
中创建的相同对象,而是在创建新对象(它与在 viewWillAppear
中创建的对象没有任何关系) >).比起你从它的通知中辞职,仍然因为它不是你之前创建并签署给他(使用 KVO)的同一个对象,这样的辞职不会导致所需的结果。您需要做的是将第一个创建的对象保存到某个变量,然后在需要的地方退出该变量。
其次,您不仅需要在 viewWillDissapear
方法中移除观察者,而且还需要在
deinit {
// perform the deinitialization
}
然后你会确定,如果你的对象被删除,它也会从通知中退出。
您的错误消息表明已为通知签名的对象已标记为已删除,但仍未注销,即使已删除也会收到通知(听起来不太好,因为他所属的内存可能已被使用对于其他一些对象,这可能会导致您的应用出现未定义的行为)。
关于ios - 为什么在页面 View Controller 中使用 KVO 进行观察时应用程序崩溃?以及如何使 KVO 生效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38940357/