a

Câu hỏi Làm thế nào để bạn loại bỏ KVO từ một tài sản yếu?


Tôi có một cái nhìn (chúng ta sẽ gọi cái nhìn này là A) có weak tài sản để giám sát của nó (xem B). Xem A của KVO giám sát của nó, xem B. Vì tham chiếu của view A để xem B là một tài sản yếu (để ngăn chặn một chu kỳ giữ lại), làm thế nào tôi có thể loại bỏ người quan sát (A quan sát B)? Xem tham chiếu của A để xem B bị bỏ ra trước khi tôi có cơ hội xóa nó.

Một outlives B kể từ khi bộ điều khiển xem có một tham chiếu mạnh mẽ đến A. Đây là thông điệp tường trình bị rò rỉ:

An instance 0x9ac5200 of class UITableView was deallocated while key value observers were still registered with it. Observation info was leaked, and may even become mistakenly attached to some other object. Set a breakpoint on NSKVODeallocateBreak to stop here in the debugger. Here's the current observation info:
<NSKeyValueObservationInfo 0x8660360> (
<NSKeyValueObservance 0x8660320: Observer: 0x8660020, Key path: contentOffset, Options: <New: YES, Old: NO, Prior: NO> Context: 0x8660020, Property: 0x864ac80>
)

B là một UITableView. Đặt điểm ngắt tại NSKVODeallocateBreak mang lại kết quả vô ích.

Trong A's removeFromSuperview, Tôi cố gắng loại bỏ người quan sát nhưng tham chiếu A của B đã nil.

Chuyển sang unsafe_unretained và làm những việc thủ công hơn hoặc gọi điện [A removeFromSuperview] trong bộ điều khiển của chế độ xem dealloc giải quyết vấn đề. Tôi muốn biết cách giải quyết điều này bằng cách sử dụng weak tài sản mặc dù.

Đây là mã có liên quan: https://gist.github.com/2822776


35
2018-05-29 04:48


gốc


Tệ của tôi ... +1 dù sao đi nữa. - CodaFi


Các câu trả lời:


Tôi tìm thấy bất kỳ loại mã yêu cầu đặc biệt cho trường hợp này thực sự không cần thiết như loại bỏ có thể được tự động.

Với sự ra mắt của ARC, Apple nên đã cung cấp tự động loại bỏ các nhà quan sát có thể sửa chữa các trường hợp như thế này, nhưng tiếc là họ đã không. Nhưng tôi đã tạo danh mục của riêng mình để thêm tính năng thiếu này: https://github.com/krzysztofzablocki/SFObservers Tôi đã giải thích cách tôi đã quản lý điều đó trên blog của mình: http://www.merowing.info/2012/03/automatic-removal-of-nsnotificationcenter-or-kvo-observers/

Nếu bạn nhìn vào giải pháp của tôi, bạn sẽ nhận thấy rằng, nó đảm bảo rằng mã gốc được gọi, ngay cả khi một trong các phương thức gọi các phương thức khác, để ngay cả khi apple thay đổi hành vi bên trong, danh mục vẫn hoạt động tốt :)


2
2018-05-29 10:28



SFOvservers của bạn trông thật tuyệt. Tôi đã hy vọng sử dụng một giải pháp ít thông minh hơn. Những thứ rắc rối trên NSObject hơi đáng sợ. Ai biết được những gì họ sẽ thay đổi trong iOS 6. - Sam Soffes
Đó là lý do tại sao giải pháp của tôi không giả định bất kỳ thứ tự các phương thức gốc nào và thay vào đó gọi mã gốc :-) Vì vậy, đó là bằng chứng trong tương lai nếu chúng thay đổi bất kỳ thứ gì. - Krzysztof Zabłocki


Bạn có thể xác định một thuộc tính yếu rõ ràng tham chiếu đến superview và sau đó quan sát self với một con đường chính như @"propertyReferringSuperview.propertyOfSuperview"? Khi bạn nhận được thông báo KVO, bạn kiểm tra xem self.propertyReferringSuperview == nil và ngừng quan sát @"propertyReferringSuperview.propertyOfSuperview".


1
2018-05-29 09:15



Tôi đã thử phương pháp này. Khi tham chiếu yếu đến superview được niled ra, KVO không cháy. - Sam Soffes
Thật là xấu hổ ... Có lẽ cố gắng để chèn dọn dẹp vào setter tùy chỉnh setPropertyReferringSuperview:? Tôi hy vọng nó được gọi khi tham chiếu yếu trở thành nil. Trên thực tế, bạn có thể bắt đầu và ngừng quan sát ngay trong setter này. - Stream
Đây là một câu trả lời tuyệt vời. Bạn không cần phải loại bỏ mình như một người quan sát khi superview được niled ra. Bạn có thể vẫn là một người quan sát cho đến khi bạn được dealloced. Vì vậy, chỉ cần đăng ký để nghe trong init (ngay cả khi tài sản của bạn là nil này là tốt), sau đó unregister trong dealloc (hoặc deinit). - plivesey


Thay vì thêm thuộc tính yếu, bạn chỉ có thể sử dụng superview tài sản và thực hiện willMoveToSuperview: để thêm / loại bỏ các quan sát KVO.

- (void)willMoveToSuperview:(UIView *)newSuperview {
    [self.superview removeObserver:self forKeyPath:@"contentOffset" context:context];
    [newSuperview addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:context];
    [super willMoveToSuperview:newSuperview]; // optional as default implementation does nothing
}

0
2018-05-29 10:33



Khi nào willMoveToSuperview: được gọi, thuộc tính yếu tham chiếu chế độ xem B (hoặc scrollView trong Gist) đã nil. - Sam Soffes
Có nhưng bạn đã nói rằng quan điểm B là giám sát của A. Vì vậy, bạn không cần cho scrollView bất động sản. Chỉ dùng superview. - Nicolas Bachschmidt