2012-04-26 17 views
17

Nhìn vào ví dụ khác nhau của Apple (ví dụ Add Music) trong đó tôi thấy họ thêm các quan sát viên để mặc định NSNotificationCenter trong viewDidLoad, sau đó loại bỏ chúng trong dealloc. Điều này có vẻ nguy hiểm vì viewDidLoad có thể được gọi nhiều lần mà không cần gọi số dealloc. Điều này sau đó sẽ thêm cùng một người quan sát nhiều lần, khiến cho trình xử lý được gọi nhiều lần.Thêm và xóa các quan sát viên đến NSNotificationCenter trong một UIViewController

Một giải pháp cho việc này cũng sẽ loại bỏ người quan sát trong viewDidUnload, nhưng điều này có nghĩa là người quan sát tương tự có thể bị xóa lần thứ hai trong dealloc.

Tôi đang thiếu gì?

+3

Tôi không nghĩ rằng việc xóa người quan sát không tồn tại có bất kỳ tác động bất lợi nào. – jbat100

+0

@ jbat100 Cảm ơn. Tôi chắc chắn nghĩ rằng việc loại bỏ các nhà quan sát trong cả hai dealloc và viewDidUnload là cách duy nhất để đi. – Undistraction

Trả lời

24

Có rất nhiều cuộc thảo luận về việc xóa thông báo theo đúng cách. Ví dụ:

tôi khuyên bạn nên tháo các nhà quan sát trong viewWillDisappear (hoặc viewDidDisappear) và viewDidUnload phương pháp vòng đời. (Lưu ý:viewDidUnload được chấp nhận và không nên được thực hiện trong iOS6 +, xem iOS 6 - viewDidUnload migrate to didReceiveMemoryWarning?)

Một lưu ý quan trọng:

viewDidUnload không được đảm bảo để được gọi là - nó không phải là một phương pháp vòng đời tiêu chuẩn.

Từ Apple doc:

viewDidUnload Khi một tình trạng bộ nhớ thấp xảy ra và quan điểm quan điểm điều chỉnh dòng điện của không cần thiết, hệ thống có thể lựa chọn để loại bỏ những quan điểm từ bộ nhớ . Phương pháp này được gọi sau khi chế độ xem của trình điều khiển chế độ xem có được phát hành và là cơ hội để bạn thực hiện bất kỳ lần dọn dẹp cuối cùng nào.

Thay vào đó, dealloc được gọi bất cứ khi nào số tham chiếu cho người nhận đó bằng không.

Hy vọng điều đó sẽ hữu ích.

Sửa

Vì lợi ích của sự hoàn chỉnh, bạn có thể nhìn thấy liên kết này về cách avoid-nsnotification-removeobserver. Liên kết cung cấp một số hướng dẫn hữu ích để xóa người quan sát (xem thêm các nhận xét). Tác giả thực hiện nó trong các phương thức viewDidAppear/viewDidDisappear kể từ viewWillAppearviewWillDisappear không phải lúc nào cũng được gọi chính xác trong nhiều ứng dụng. Đó là sự lựa chọn của bạn.

Nếu bạn muốn đảm bảo xóa người quan sát theo đúng cách, hãy hủy đăng ký phương thức đó theo phương pháp dealloc hoặc khi chế độ xem được tải hoàn toàn như bạn đã viết trong nhận xét thứ hai. Nhưng hãy chắc chắn rằng dealloc sẽ được gọi trong tương lai. Nói cách khác, như tôi đã đề cập, nếu bộ điều khiển tiếp tục sống động vì một số đối tượng khác có tham chiếu đến nó, phương thức sẽ không bao giờ được gọi. Trong trường hợp này bộ điều khiển tiếp tục nhận được thông báo.

+0

Cảm ơn. Nhưng như bạn đề cập đến; 'viewDidUnload không được gọi trước phương thức dealloc. Đôi khi một dealloc của VC sẽ được gọi mà không có viewDidUnload được gọi và, trong tình huống này, sử dụng gợi ý của bạn có nghĩa là VC được để lại như một người quan sát sau khi nó được deallocated như viewWillDisappear/viewDidunload sẽ không bao giờ được gọi. Hoặc là viewWillDisappear hoàn toàn đảm bảo được gọi trước dealloc? – Undistraction

+1

@ 1ndivisible * viewWillDisappear * được gọi trước khi chế độ xem biến mất khỏi màn hình. Điều đó có nghĩa là khi bạn xóa bộ điều khiển của khung nhìn khỏi màn hình (ví dụ: bộ điều khiển được bật từ bộ điều khiển điều hướng) thì phương thức đó được gọi. Tôi đã thêm bản chỉnh sửa cho bạn. –

+1

Tốt. Liên kết tránh-nsnotification-removeobserver là một liên kết tốt đẹp. Không biết. – Undistraction

2

Tại sao bạn không làm điều đó trong viewWillAppear/viewDidDisappear? Bạn chỉ quan tâm đến các thông báo khi chế độ xem của bạn hiển thị, đúng không?

+0

Nhưng theo như tôi biết không có đảm bảo rằng viewDidDisappear được gọi nếu đối tượng được deallocated. Nếu không, đối tượng được để lại như một người quan sát sau khi nó được giải phóng. – Undistraction

+0

Rõ ràng chúng sẽ luôn được gọi. (Xem bên trên) – Undistraction

+1

Không có trong các ứng dụng nhất định mà người dùng quan tâm khi chế độ xem không hiển thị trạng thái dữ liệu cập nhật tức là – jini

2
- (void)viewWillAppear:(BOOL)animated 
{ 
    [super viewWillAppear:animated]; 
    [[NSNotificationCenter defaultCenter] addObserver:self .........] 
} 

- (void)viewWillDisappear:(BOOL)animated 
{ 
    [super viewWillDisappear:animated]; 
    [[NSNotificationCenter defaultCenter] removeObserver:self .........]; 
} 
0

Bạn có thể thêmObserver trong chế độ xemCó thể xóa và removeObserver trong chế độ xemLàm mờ. nhưng viewWillAppear có thể được gọi nhiều lần. vì vậy bạn có thể xóa Thông báo trước rồi addObserver.

-(void)viewWillAppear:(BOOL)animated{ 
    [super viewWillAppear:YES]; 
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIKeyboardWillShowNotification" object:nil]; 
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIKeyboardWillHideNotification" object:nil]; 
    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(keyboardWillShow:)name:@"UIKeyboardWillShowNotification"object:nil]; 
    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(keyboardWillHide:)name:@"UIKeyboardWillHideNotification"object:nil]; 
} 

-(void)viewWillDisappear:(BOOL)animated{ 
[super viewWillDisappear:YES]; 
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIKeyboardWillShowNotification" object:nil]; 
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIKeyboardWillHideNotification" object:nil]; 
} 
1

Đối với những người mò mẫm trên trang này gần đây, việc xóa người quan sát có thể không cần thiết nữa. Các "Discussion" section of the addObserver(_:selector:name:object:) docs nói:

Nếu mục tiêu ứng dụng của bạn iOS 9.0 và phiên bản hệ điều hành MacOS hoặc 10.11 và sau đó, bạn không cần phải unregister một người quan sát trong phương pháp dealloc của nó. Nếu không, bạn nên gọi removeObserver(_:name:object:) trước khi người quan sát hoặc bất kỳ đối tượng nào được truyền cho phương pháp này được deallocated.