Terminar la aplicación debido a la exception no detectada 'NSRangeException', motivo: 'No se puede eliminar un observador – ios

Estoy desarrollando la aplicación ios usando swift. Estoy usando xcode7.0.1. con TableViewController. Quiero expandir cuando hago clic en fila y queuepso cuando hago clic nuevamente. Estoy siguiendo el tutorial de gitHub . Ahora me enfrento a la Terminating app due to uncaught exception 'NSRangeException', reason: 'Cannot remove an observer el error Terminating app due to uncaught exception 'NSRangeException', reason: 'Cannot remove an observer for the key path "frame" from <X.expandTips 0x145d8d20> because it is not registenetworking as an observer.'

Espero que la siguiente línea de código provoque el problema.

Mi código de class 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() } } 

Y en mi código TableViewController:

 override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { (cell as! expandTips) . WatchFrameChanges() } override func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { (cell as! expandTips) . ignoreFrameChanges() } override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { if (indexPath == selectedIndexPath ){ return expandTips.expandedHeight }else { return expandTips.defaultHeight } } 

Soy nuevo en ios. Espero que sea un problema simple. Por favor, alguien me ayude a resolver esto.

No sé cuáles son los detalles que se deben publicar aquí. Por favor comente si quiero agregar más detalles.

Del comentario de @Leandros encontré la solución. Solo rastrea al observador usando una variable booleana.

Uso del siguiente código, encontré la solución:

  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() } 

La eliminación del observador KVO arroja una exception, si no hay un observador registrado.

Lamentablemente, no hay forma de verificar si un observador está registrado. Una solución conocida es simplemente tomar una exception como esta (Objective-C):

 @try { [object removeObserver:self forKeyPath:NSStringFromSelector(@selector(isFinished))]; } @catch (NSException * __unused exception) {} 

Para hacerlo en Swift, debes usar Swift 2.1, ya que hasta que faltó soporte para try {} catch {} . Puedes ver cómo funciona en 2.1 aquí .

Corrección: aunque Swift 2 introdujo su propia convención de event handling errores, con do/try/catch palabras key do/try/catch , no significa lo mismo que en Objective-C, y todavía hay (a partir de Swift 2.1 y Xcode 7.1) de ninguna manera en Swift para manejar NSExceptions lanzadas desde las bibliotecas del sistema que no sea escribir código Objective-C para @catch them, y luego llamar a ese código desde Swift.

Puede leer más sobre KVO en general aquí , que también tiene una sección sobre la cancelación segura de la suscripción que menciona este desafortunado layout.