Objective c 弱引用';关联';关联对象中的对象

Objective c 弱引用';关联';关联对象中的对象,objective-c,uiscrollview,automatic-ref-counting,weak-references,associated-object,Objective C,Uiscrollview,Automatic Ref Counting,Weak References,Associated Object,以下代码导致NSInternalConsistencyException:由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因是:“当键值观察者仍向其注册时,类UIScrollView的实例0x7fd3a1010000被解除分配。 实际上,问题在于,当在Observer上调用dealoc时,它对UIScrollView的引用已经被取消,并且\u removeObserver是不可操作的 我知道这可能与关联对象的解除分配方式有关,但实际上(38:

以下代码导致NSInternalConsistencyException:
由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因是:“当键值观察者仍向其注册时,类UIScrollView的实例0x7fd3a1010000被解除分配。

实际上,问题在于,当在Observer上调用
dealoc
时,它对UIScrollView的引用已经被取消,并且
\u removeObserver
是不可操作的

我知道这可能与关联对象的解除分配方式有关,但实际上(38:14)在删除弱引用之前删除关联对象的位置并不清楚

我发现的一个解决方法是使UIScrollView属性
不安全\u无法保存

  • 有人确切地知道为什么会发生这种情况吗
  • 这里推荐的解决方案是什么
谢谢

@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
@接口观察者:NSObject
@属性(非原子,弱)UIScrollView*scrollView;
@结束
@执行观察员
-(无效)解除锁定{
[自我清除观察者];
}
-(void)setScrollView:(UIScrollView*)滚动视图{
如果(滚动视图){
[自我清除观察者];
}
_scrollView=scrollView;
[self.scrollView addObserver:self forKeyPath:@“contentOffset”选项:NSKeyValueObservingOptionNew context:nil];
}
-(void)observeValueForKeyPath:(NSString*)对象的键路径:(id)对象更改:(NSDictionary*)更改上下文:(void*)上下文{}
-(无效){
[self.scrollView removeObserver:self forKeyPath:@“contentOffset”];
}
@结束
@界面UIScrollView(测试)
@结束
@实现UIScrollView(测试)
-(无效)测试设置{
观察员*观察员=[新观察员];
observer.scrollView=self;
objc_setAssociatedObject(自、@“观察者”、观察者、objc_关联_保留_非原子);
}
@结束
然后:

UIScrollView *scrollView = [UIScrollView new];
[scrollView test_setup];
// scrollView is deallocated <--- EXCEPTION
UIScrollView*scrollView=[UIScrollView新建];
[滚动视图测试设置];
//scrollView已解除分配