由于未捕获异常而终止应用程序';nsrange异常';,原因:';无法删除观察者-ios

由于未捕获异常而终止应用程序';nsrange异常';,原因:';无法删除观察者-ios,ios,swift,xcode7,Ios,Swift,Xcode7,我正在使用swift开发ios应用程序。我使用的是xcode7.0.1。使用TableViewController。我想在单击行时展开,再次单击时折叠。我正在跟随来自的教程。现在,由于未捕获的异常“NSRangeException”,我面临终止应用程序的错误,原因是:'无法从中删除关键路径“frame”的观察者,因为它未注册为观察者。 我希望下面的代码行将导致该问题 我的UITableViewCell类代码: func checkHeight(){ expandaple_view

我正在使用swift开发ios应用程序。我使用的是xcode7.0.1。使用TableViewController。我想在单击行时展开,再次单击时折叠。我正在跟随来自的教程。现在,由于未捕获的异常“NSRangeException”,我面临终止应用程序的错误
,原因是:'无法从中删除关键路径“frame”的观察者,因为它未注册为观察者。

我希望下面的代码行将导致该问题

我的UITableViewCell类代码:

func checkHeight(){
        expandaple_view.hidden = (frame.size.height < expandTips.expandedHeight)
    }
    
    func WatchFrameChanges() {
        addObserver(self , forKeyPath: "frame", options: .New, context: nil )
        checkHeight() 
    }
    
    func ignoreFrameChanges(){
       
        removeObserver(self, forKeyPath: "frame")
        
    }
    
    override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
        if keyPath == "frame"{
            checkHeight()
        }
    }
我是ios新手。我希望这一定是个简单的问题。请有人帮我解决这个问题


我不知道需要在这里发布哪些详细信息。如果我想添加更多详细信息,请发表评论。

如果没有注册观察器,则删除KVO观察器会引发异常

不幸的是,无法检查观察员是否已注册。一个众所周知的解决方法是捕获如下异常(Objective-C):

要在Swift中实现这一点,必须使用Swift 2.1,因为它缺乏对
try{}catch{}
的支持。您可以在2.1中看到它是如何工作的

更正:尽管Swift 2引入了自己的错误处理约定,使用了
do/try/catch
关键字,但这些关键字的含义与Objective-C中的不同,并且仍然存在(从Swift 2.1和Xcode 7.1开始)Swift无法处理从系统库抛出的NSException,只能将Objective-C代码写入
@catch
中,然后从Swift调用该代码


您可以阅读有关KVO的更多信息,其中还有一节关于安全退订的内容,其中提到了这一不幸的设计。

从@Leandros的评论中,我找到了解决方案。只需使用布尔变量跟踪观察者

使用以下代码,我找到了解决方案:

 var frameAdded = false
 func checkHeight(){

        expanding_view.hidden = (frame.size.height < expandTips.expandedHeight)
    }

    func WatchFrameChanges() {
        if(!frameAdded){
        addObserver(self , forKeyPath: "frame", options: .New, context: nil )
            frameAdded = true
        }
    }

    func ignoreFrameChanges() {
          if(frameAdded){
        removeObserver(self, forKeyPath: "frame")
            frameAdded = false
        }
    }

    override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
        if keyPath == "frame"{
            checkHeight()
        }
    }
    deinit {
        print("deinit called");
        ignoreFrameChanges()
    }
var frameAdded=false
func checkHeight(){
expanding_view.hidden=(frame.size.height
我是这样改变的。func ignoreFrameChanges()抛出->Void{do{try removeObserver(self,forKeyPath:“frame”)}捕获{print(error)}。现在我面临两个警告:“在‘try’表达式中没有对抛出函数的调用”和“‘catch’块不可访问,因为‘do’块中没有抛出错误”。而且仍然是应用程序关闭看起来,Swift仍然不能捕捉到NSException,就像Objective-C一样。你现在有两种方法来解决你的问题,一种是丑陋的,另一种是好的。丑陋的方法是用Objective-C编写那部分代码,并从Swift调用它,好的方法是,如果您已经删除了观察者,则保持跟踪,而不是简单地不调用它,如果它已经被删除。我已经创建了一个NSObject类别,该类别提供了一个安全的方法RemoveObserver:forKeyPath:您必须从Swift调用该类别,以便捕获当观察者当前未注册时引发的NSException。我几乎完全确定该代码来自我的YouTube视频,因此我将继续并在此处链接到它(). KVO de register的修复实际上已经对存储库()进行了。是的,我正在关注这个GitHub项目。此问题已由@mattiaskronberg注册。我从这个Pastebin链接中找到了解决方案。感谢您对解决方案的快速响应。
@try {
    [object removeObserver:self forKeyPath:NSStringFromSelector(@selector(isFinished))];
} @catch (NSException * __unused exception) {}
 var frameAdded = false
 func checkHeight(){

        expanding_view.hidden = (frame.size.height < expandTips.expandedHeight)
    }

    func WatchFrameChanges() {
        if(!frameAdded){
        addObserver(self , forKeyPath: "frame", options: .New, context: nil )
            frameAdded = true
        }
    }

    func ignoreFrameChanges() {
          if(frameAdded){
        removeObserver(self, forKeyPath: "frame")
            frameAdded = false
        }
    }

    override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
        if keyPath == "frame"{
            checkHeight()
        }
    }
    deinit {
        print("deinit called");
        ignoreFrameChanges()
    }