12

Tôi bối rối vì sao người quan sát không bao giờ bị loại bỏ trong đoạn mã sau. Trong viewDidAppear của tôi, tôi có như sau:Tại sao không loại bỏ Observer khỏi NSNotificationCenter: addObserverForName: usingBlock được gọi là

-(void)viewDidAppear:(BOOL)animated{ 

id gpsObserver = [[NSNotificationCenter defaultCenter] 
          addObserverForName:FI_NOTES[kNotificationsGPSUpdated] 
          object:nil 
          queue:[NSOperationQueue mainQueue] 
          usingBlock:^(NSNotification *note){ 

           NSLog(@"run once, and only once!"); 

       [[NSNotificationCenter defaultCenter] removeObserver:gpsObserver]; 

     }]; 

} 

Các quan sát viên không bao giờ bị loại bỏ và tuyên bố là đầu ra mỗi khi thông báo được gửi ra. Bất cứ ai có thể cung cấp bất kỳ hướng dẫn?

Trả lời

28

Khi khối được đẩy lên ngăn xếp bằng addObserverForName: phương thức chưa được trả lại nên gpsObserver là không (dưới ARC) hoặc rác/không xác định (không phải dưới ARC). Khai báo biến bằng cách sử dụng __block bên ngoài và điều này sẽ hoạt động.

__block __weak id gpsObserver; 

gpsObserver = [[NSNotificationCenter defaultCenter] 
          addObserverForName:FI_NOTES[kNotificationsGPSUpdated] 
          object:nil 
          queue:[NSOperationQueue mainQueue] 
          usingBlock:^(NSNotification *note){ 

           NSLog(@"run once, and only once!"); 

       [[NSNotificationCenter defaultCenter] removeObserver:gpsObserver]; 

     }]; 

Tôi đã thêm __weak để đảm bảo không có rò rỉ bộ nhớ (theo câu trả lời của Matt). Mã chưa được kiểm tra.

+0

Điều đó có ý nghĩa và hoạt động như mong đợi; cảm ơn sự giúp đỡ của bạn. – warpedspeed

11

Tôi thấy rằng trên thực tế có rò rỉ bộ nhớ trừ khi người quan sát được đánh dấu cả hai __block__weak. Sử dụng dụng cụ để đảm bảo rằng self không bị quá tải; Tôi cá là nó. Tuy nhiên, điều này hoạt động chính xác (từ mã thực tế của tôi):

__block __weak id observer = [[NSNotificationCenter defaultCenter] 
    addObserverForName:@"MyMandelbrotOperationFinished" 
    object:op queue:[NSOperationQueue mainQueue] 
    usingBlock:^(NSNotification *note) { 
     // ... do stuff ... 
     [[NSNotificationCenter defaultCenter] 
      removeObserver:observer 
      name:@"MyMandelbrotOperationFinished" 
      object:op]; 
}]; 
+0

Tôi rất thích nó nếu họ giới thiệu phương pháp tương đương mà thực sự không yêu cầu bạn phải kiên trì các nhà quan sát mà là sử dụng chính mình như một, chỉ đơn giản là sử dụng các khối thay vì các bộ chọn. – Eugene

+2

Bạn không cần đặt 'observer'' __weak' nếu bạn đặt nó thành 'nil' sau khi xóa nó khỏi' NSNotificationCenter'. Tôi đã kiểm tra điều này với dụng cụ. –

+0

Đây là một đoạn mã tốt, thưa ngài. – Andy

Các vấn đề liên quan