ios - 为什么在页面 View Controller 中使用 KVO 进行观察时应用程序崩溃?以及如何使 KVO 生效?

标签 ios swift uipageviewcontroller key-value-observing uicontainerview

我正在尝试使用 KVO 来观察在我的页面 View Controller 的子内容 View Controller 的 ScrollView 中使用拖动时的更新变化,但是当应用程序启动时,它崩溃了说:

“由于未捕获的异常‘NSInternalInconsistencyException’而终止应用程序,原因:‘类 KVOPageVC.ContentViewController 的实例 0x7ff003d3f5b0 已被释放,而键值观察者仍在其中注册。”

下面是我的代码和截图:

应用截图 enter image description here

代码

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/

相关文章:

ios - 如何在 NSURL 中使用非英文字符串?

ios - 获取 UIImageView 中的图像数组(在 UIPageViewController 中)

swift - UIpageViewController 和定时器

ios - Flutter 启动 iOS 应用程序时显示黑屏

ios - CFStringTransform线程安全且可重入吗?

ios - 创建网页并从中异步加载应用程序数据

ios - 以编程方式绘制 iOS 7 风格的圆圈

objective-c - iOS : How to implement a bookmark for ePub reader?

ios - UIWebView 没有完成加载?

iOS 呈现多达 30 个 View Controller (ARC) 的最佳方式