Слабая ссылка на "ассоциативный" объект в связанном объекте

Следующий код приводит к NSInternalConsistencyException: Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x7fd3a1010000 of class UIScrollView was deallocated while key value observers were still registered with it.,

Практически, проблема в том, что когда dealloc вызывается в Observer, ссылка на UIScrollView уже обнулена, а _removeObservers это неоперация.

Я понимаю, что это может иметь отношение к способу освобождения связанных объектов, но на самом деле это неясно из https://developer.apple.com/videos/play/wwdc2011-322/ (38:14), где связанные объекты стираются до того, как будут удалены слабые ссылки.

Обходной путь, который я нашел, состоит в том, чтобы сделать свойство UIScrollView unsafe_unretained,

  • Кто-то точно знает, почему это происходит?
  • Какое рекомендуемое решение здесь?

Спасибо!

@interface Observer : NSObject
@property (nonatomic, weak) UIScrollView *scrollView;
@end

@implementation Observer

- (void)dealloc {
    [self _removeObservers];
}

- (void)setScrollView:(UIScrollView *)scrollView {
    if (_scrollView) {
        [self _removeObservers];
    }
    _scrollView = scrollView;
    [self.scrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {}

- (void)_removeObservers {
    [self.scrollView removeObserver:self forKeyPath:@"contentOffset"];
}

@end

@interface UIScrollView (Test)
@end

@implementation UIScrollView (Test)

- (void)test_setup {
    Observer *observer = [Observer new];
    observer.scrollView = self;
    objc_setAssociatedObject(self, @"observer", observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end

А потом:

UIScrollView *scrollView = [UIScrollView new];
[scrollView test_setup];
// scrollView is deallocated <--- EXCEPTION

0 ответов