2016-06-12 3 views
1

コントローラにスクロールビューがあります。スクロールビューには1つのサブビューがあります。サブビューは同時にスクロールビューのオブザーバです。私はサブビューのwillMoveToSuperview:が呼ばれたときにオブザーバーを削除します。しかし、コントローラが終了すると、アプリがクラッシュしました。ここではサンプルコードは次のとおりです。KVOオブザーバを削除するとAPPがクラッシュする

@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 

私はwillMoveToSuperviewself.scrollViewを印刷するとき、それはnullを示しています。私がMyViewのプロパティscrollViewをunsafe_unretainedに変更すると、アプリケーションはクラッシュしません。 私は混乱しています。なぜ弱いのではないscrollView作品。 scrollViewがunsafe_unretainedのときに私はぶら下がっているポインタを読んでいますか?その状況に対するより良い解決策がありますか?

+0

クラッシュですか? EXC_BAD_ACCESS? –

+0

@tryキャッチでコードを削除する – Nick

+0

@AndreyChernukhaクラッシュは 'removeObserver:forKeyPath:' '2016-06-12 22:39:53.752 ScrollView [20987:7043889]を呼び出していないと同じです*** uncaught exception 'NSInternalInconsistencyException'、reason: 'UIScrollViewクラスのインスタンス0x7fd01b824400が、キー値オブザーバがまだ登録されている間に割り当て解除されました。現在の観測情報:コンテキスト:0x0の、プロパティ:> 「) ' – Bing

答えて

1

ここでの問題はscrollViewweakというポインタが既にnil(割り当てられていない)と呼ばれています。 しかし、scrollViewは完全に割り当て解除されていないと思います(メモリが解放されていない)thatsなぜunsafe_unretained参照を使用してオブザーバーを削除しても何とか動作します。しかし、それはぶら下がっているポインタ参照であり、あなたはそれに頼るべきではありません。

+1

willMoveToSuperviewのremoveObserverが悪いデザインかもしれないと思います。 – Bing

+0

ええ、あなたは、いつ割り振り解除されるのか判断できないオブジェクトは観察しないでください。 – srvv

関連する問題