2015-10-02 1 views
3

Я разрабатываю приложение ios с помощью быстрого доступа. Я использую xcode7.0.1. с TableViewController. Я хочу расширить, когда я нажимаю строку и рушится, когда снова нажимаю ее. Я следую учебнику от gitHub. Теперь я столкнулся с ошибкой Terminating app due to uncaught exception 'NSRangeException', reason: 'Cannot remove an observerfor the key path "frame" from <X.expandTips 0x145d8d20> because it is not registered as an observer.'Завершение приложения из-за неотображенного исключения «NSRangeException», причина: «Не удается удалить наблюдателя - ios

Надеюсь, следующая строка кода вызовет проблему.

код Мой 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() 
     } 
    } 

И в моем 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 
     } 
    } 

Я новичок в ИОС. Надеюсь, это должна быть простая проблема. Пожалуйста, помогите мне решить эту проблему.

Я не знаю, какие детали нужно размещать здесь. Прошу прокомментировать, если я хочу добавить более подробную информацию.

+1

Я почти полностью уверен, что этот код из моего видео на YouTube, так что я буду идти вперед и ссылку на него здесь (https: // WWW .youtube.com/смотреть? v = VWgr_wNtGPM). Это исправление для де-регистра KVO фактически было уже сделано в репозитории (https://github.com/rcdilorenzo/Cell-Expander). –

+0

Да, именно я следую этому проекту GitHub. Этот вопрос уже зарегистрирован @mattiaskronberg. Я нашел решение из этой ссылки в Pastebin. http://pastebin.com/VaRmuYfU – Amsheer

ответ

11

Из комментария @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() 
    } 
+0

Спасибо за быстрый ответ на решение. – felixwcf

5

Извлечение наблюдателя KVO бросает исключение, если нет зарегистрированного наблюдателя.

К сожалению, не существует способа проверить, зарегистрирован ли наблюдатель. Хорошо известно, обходной путь, чтобы просто поймать исключение, как это (Objective-C):

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

Чтобы сделать это в Swift, вы должны использовать Swift 2.1, так как до тех пор, чем не хватало поддержки try {} catch {}. Вы можете увидеть, как это работает в 2.1 here.

Исправление: Хотя Swift 2 представила свою собственную конвенцию обработки ошибок, с do/try/catch ключевых слов, это не означает то же самое, что они делают в Objective-C, и есть до сих пор (по состоянию на Swift 2.1 и Xcode 7.1) никак не в Swift обрабатывать NSExceptions, выписанные из системных библиотек, кроме как писать код Objective-C до @catch, а затем вызывать этот код из Swift.

Вы можете узнать больше о KVO вообще here, в котором также есть раздел о безопасной отписке, в которой упоминается этот неудачный дизайн.

+0

Я меняюсь вот так. функ ignoreFrameChanges() броски -> Пустота { сделать { попробовать removeObserver (самоощущение, forKeyPath: "кадр") } поймать { печать (ошибка) } }.Теперь я столкнулся с двумя предупреждениями: «Нет вызовов для металирования функций внутри« try »expression» и «catch» блок недостижим, потому что в блок do do не попадают ошибки. – Amsheer

+0

И все же закрытие приложения – Amsheer

+2

Похоже, Swift все еще не может поймать NSExceptions, например Objective-C. У вас есть два способа исправить вашу проблему, один уродливый и один хороший. Уродливым способом является запись этой части кода в Objective-C и вызов ее из Swift, и хорошим способом является отслеживание, если вы уже удалили наблюдателя, а не просто не называть его, если он уже удален , – Leandros