Bing
Bing

Reputation: 361

APP crashes when remove KVO observer

I have a scroll view in controller. The scroll view has one subview. The subview is an observer of the scroll view at the same time. I remove the observer when subview's willMoveToSuperview: called. But when the controller dismissed, app crashed. Here are the sample codes:

@interface MyView : UIView

@property (nonatomic, weak) UIScrollView *scrollView;

@end

@implementation MyView

- (instancetype)initWithFrame:(CGRect)frame scrollView:(UIScrollView *)scrollView {
    self = [super initWithFrame:frame];
    if (self) {
        self.scrollView = scrollView;
        [scrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
    }
    return self;
}

- (void)willMoveToSuperview:(UIView *)newSuperview {
    [super willMoveToSuperview:newSuperview];

    if (!newSuperview) {
        [self.scrollView removeObserver:self forKeyPath:@"contentOffset"];
        self.scrollView = nil;
    }
}

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

@end

@interface SecondViewController ()

@end

@implementation SecondViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
    scrollView.backgroundColor = [UIColor whiteColor];
    [self.view addSubview:scrollView];

    MyView *view = [[MyView alloc] initWithFrame:CGRectMake(100, 200, 100, 100) scrollView:scrollView];
    [scrollView addSubview:view];
}

@end

When I print self.scrollView in willMoveToSuperview, it shows null. When I change the property scrollView in MyView to unsafe_unretained, app will not crash. So I am confused. Why not weak scrollView work. Am I reading dangling pointer when scrollView is unsafe_unretained? Are there better solution to that situation?

Upvotes: 2

Views: 907

Answers (1)

srvv
srvv

Reputation: 623

The issue here is by the time willMoveToSuperview is called the scrollView weak pointer is already nil(deallocated). But it think scrollView not completely deallocated(memory not released) thats why when you use unsafe_unretained reference to remove observer it works somehow. But it is a dangling pointer reference and you should not rely on that.

Upvotes: 1

Related Questions