Objective-C: จะลบผู้สังเกตการณ์สำหรับ NSNotification ได้ที่ไหน


102

ฉันมีคลาส C วัตถุประสงค์ ในนั้นฉันสร้างเมธอด init และตั้งค่า NSNotification ในนั้น

//Set up NSNotification
[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(getData)
                                             name:@"Answer Submitted"
                                           object:nil];

ฉันจะตั้งค่าที่ไหน[[NSNotificationCenter defaultCenter] removeObserver:self]ในชั้นเรียนนี้ ฉันรู้ว่าสำหรับ a UIViewControllerฉันสามารถเพิ่มเข้าไปในviewDidUnloadวิธีการได้ดังนั้นฉันต้องทำอะไรถ้าฉันเพิ่งสร้างคลาส c วัตถุประสงค์?


ฉันใส่ไว้ในวิธีการ dealloc
onnoweb

1
วิธีการ dealloc ไม่ได้สร้างขึ้นโดยอัตโนมัติสำหรับฉันเมื่อฉันสร้างคลาส c วัตถุประสงค์ดังนั้นฉันจึงสามารถเพิ่มเข้าไปได้หรือไม่?
Zhen

ใช่คุณสามารถนำไปใช้-(void)deallocและเพิ่มremoveObserser:selfเข้าไปได้ วิธีนี้เป็นวิธีที่แนะนำมากที่สุดremoveObservers:self
petershine

ยังสามารถใส่deallocวิธีการใน iOS 6 ได้หรือไม่?
wcochran

2
ใช่คุณสามารถใช้ dealloc ในโปรเจ็กต์ ARC ได้ตราบเท่าที่คุณไม่ได้เรียกใช้ [super dealloc] (คุณจะได้รับข้อผิดพลาดของคอมไพเลอร์หากคุณเรียกใช้ [super dealloc]) และใช่คุณสามารถใส่ removeObserver ของคุณใน dealloc ได้อย่างแน่นอน
ฟิลิป

คำตอบ:


112

คำตอบทั่วไปคือ "ทันทีที่คุณไม่ต้องการการแจ้งเตือนอีกต่อไป" เห็นได้ชัดว่านี่ไม่ใช่คำตอบที่น่าพึงพอใจ

ผมขอแนะนำว่าคุณเพิ่มการเรียก[notificationCenter removeObserver: self]ในวิธีการdeallocของการเรียนเหล่านั้นซึ่งคุณตั้งใจจะใช้ในฐานะผู้สังเกตการณ์ตามที่มันเป็นโอกาสสุดท้ายที่จะถอนการลงทะเบียนผู้สังเกตการณ์หมดจด อย่างไรก็ตามวิธีนี้จะป้องกันคุณจากการขัดข้องเนื่องจากศูนย์การแจ้งเตือนแจ้งวัตถุที่ตายแล้วเท่านั้น ไม่สามารถป้องกันรหัสของคุณจากการรับการแจ้งเตือนเมื่อวัตถุของคุณยังไม่อยู่ / ไม่อยู่ในสถานะที่สามารถจัดการกับการแจ้งเตือนได้อีกต่อไป สำหรับสิ่งนี้ ... ดูด้านบน

แก้ไข (เนื่องจากคำตอบดูเหมือนจะให้ความคิดเห็นมากกว่าที่ฉันคิด) ทั้งหมดที่ฉันพยายามจะพูดที่นี่คือ: เป็นการยากมากที่จะให้คำแนะนำทั่วไปเกี่ยวกับเวลาที่ดีที่สุดที่จะลบผู้สังเกตการณ์ออกจากศูนย์การแจ้งเตือนเนื่องจากขึ้นอยู่กับ:

  • ในกรณีการใช้งานของคุณ (สังเกตการแจ้งเตือนใดพวกเขาจะส่งเมื่อใด)
  • การใช้งานของผู้สังเกตการณ์ (พร้อมรับการแจ้งเตือนเมื่อใดไม่พร้อมเมื่อใด)
  • อายุการใช้งานที่ตั้งใจไว้ของผู้สังเกตการณ์ (มันเชื่อมโยงกับวัตถุอื่น ๆ เช่นมุมมองหรือตัวควบคุมมุมมองหรือไม่)
  • ...

ดังนั้นคำแนะนำทั่วไปที่ดีที่สุดที่ฉันสามารถทำได้คือเพื่อปกป้องแอปของคุณ ต่อสู้กับความล้มเหลวที่เป็นไปได้อย่างน้อยหนึ่งอย่างremoveObserver:เต้นรำเข้าdeallocมาเพราะนั่นคือจุดสุดท้าย (ในชีวิตของวัตถุ) ซึ่งคุณสามารถทำได้อย่างหมดจด สิ่งนี้ไม่ได้หมายความว่า: "เพียงแค่เลื่อนการลบออกจนกว่าdeallocจะมีการเรียกและทุกอย่างจะดี" ให้นำผู้สังเกตการณ์ออกทันทีที่วัตถุไม่พร้อม (หรือจำเป็น) รับการแจ้งเตือนอีกต่อไป นั่นคือช่วงเวลาที่เหมาะสมแน่นอน น่าเสียดายที่ไม่รู้คำตอบของคำถามใด ๆ ที่กล่าวมาข้างต้นฉันเดาไม่ออกด้วยซ้ำว่าช่วงเวลานั้นจะเป็นอย่างไร

คุณสามารถremoveObserver:ใช้วัตถุได้หลายครั้งอย่างปลอดภัยเสมอ(และทั้งหมดยกเว้นการโทรครั้งแรกกับผู้สังเกตการณ์ที่กำหนดจะเป็น nops) ดังนั้น: คิดเกี่ยวกับการทำ (อีกครั้ง) deallocเพื่อให้แน่ใจ แต่ก่อนอื่น: ทำในช่วงเวลาที่เหมาะสม (ซึ่งพิจารณาจากกรณีการใช้งานของคุณ)


4
สิ่งนี้ไม่ปลอดภัยกับ ARC และอาจทำให้เกิดการรั่วไหล ดูแผ่นดิสก์นี้: cocoabuilder.com/archive/cocoa/311831-arc-and-dealloc.html
MobileMon

3
@MobileMon บทความที่คุณเชื่อมโยงดูเหมือนจะเป็นประเด็นของฉัน ฉันขาดอะไรไป?
Dirk

ฉันคิดว่าควรสังเกตว่าควรลบผู้สังเกตการณ์ที่อื่นที่ไม่ใช่ dealloc ตัวอย่างเช่น viewwilldisappear
MobileMon

1
@MobileMon - ใช่ ฉันหวังว่านั่นคือจุดที่ฉันเข้าใจคำตอบของฉัน การนำผู้สังเกตการณ์ออกdeallocเป็นเพียงแนวทางสุดท้ายในการป้องกันไม่ให้แอปหยุดทำงานเนื่องจากมีการเข้าถึงวัตถุที่ไม่ได้ปันส่วนในภายหลัง แต่สถานที่ที่เหมาะสมในการยกเลิกการลงทะเบียนผู้สังเกตการณ์มักจะอยู่ที่อื่น (และมักจะเร็วกว่านั้นมากในวงจรชีวิตของวัตถุ) ฉันไม่ได้พยายามที่จะพูดที่นี่ "เฮ้แค่ทำมันdeallocแล้วทุกอย่างจะดี"
Dirk

@MobileMon "ตัวอย่างเช่นviewWillDisappear" ปัญหาในการให้คำแนะนำที่เป็นรูปธรรมคือจริงๆแล้วมันขึ้นอยู่กับชนิดของวัตถุที่คุณลงทะเบียนเป็นผู้สังเกตการณ์สำหรับเหตุการณ์ประเภทใด มันอาจจะเป็นทางออกที่เหมาะสมในการยกเลิกการลงทะเบียนผู้สังเกตการณ์ในviewWillDisappear(หรือviewDidUnload) สำหรับUIViewControllers แต่ที่จริงๆขึ้นอยู่กับกรณีการใช้งาน
Dirk

39

หมายเหตุ: ผ่านการทดสอบแล้วและทำงานได้ 100%

รวดเร็ว

override func viewWillDisappear(animated: Bool){
    super.viewWillDisappear(animated)

    if self.navigationController!.viewControllers.contains(self) == false  //any other hierarchy compare if it contains self or not
    {
        // the view has been removed from the navigation stack or hierarchy, back is probably the cause
        // this will be slow with a large stack however.

        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
}

PresentedViewController

override func viewWillDisappear(animated: Bool){
    super.viewWillDisappear(animated)

    if self.isBeingDismissed()  //presented view controller
    {
        // remove observer here
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
}

วัตถุประสงค์ -C

ในiOS 6.0 > versionการลบผู้สังเกตการณ์จะดีกว่าviewWillDisappearเนื่องจากviewDidUnloadเลิกใช้งานเมธอด

 [[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere];

มีหลายครั้งที่ดีกว่าremove observerเมื่อนำมุมมองออกจากไฟล์navigation stack or hierarchy.

- (void)viewWillDisappear:(BOOL)animated{
 if (![[self.navigationController viewControllers] containsObject: self]) //any other hierarchy compare if it contains self or not
    {
        // the view has been removed from the navigation stack or hierarchy, back is probably the cause
        // this will be slow with a large stack however.

        [[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere];
    }
}

PresentedViewController

- (void)viewWillDisappear:(BOOL)animated{
    if ([self isBeingDismissed] == YES) ///presented view controller
    {
        // remove observer here
        [[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere];
    }
}

8
ยกเว้นคอนโทรลเลอร์อาจยังต้องการการแจ้งเตือนเมื่อมุมมองไม่แสดง (เช่นโหลด tableView ซ้ำ)
wcochran

2
@wcochran โหลด / รีเฟรชโดยอัตโนมัติในviewWillAppear:
Richard

@Prince คุณสามารถอธิบายได้ว่าทำไม viewWillDisapper จึงดีกว่า dealloc? ดังนั้นเราจึงเพิ่มผู้สังเกตการณ์ให้กับตัวเองดังนั้นเมื่อตัวเองหลุดจากความทรงจำมันจะเรียก dealloc จากนั้นผู้สังเกตการณ์ทั้งหมดจะถูกลบนี่ไม่ใช่ตรรกะที่ดี
Matrosov Alexander

การโทรremoveObserver:selfในUIViewControllerเหตุการณ์วงจรชีวิตใด ๆเกือบจะรับประกันได้ว่าจะทำลายสัปดาห์ของคุณ อ่านเพิ่มเติม: subjective-objective-c.blogspot.com/2011/04/…
cbowns

1
วางremoveObserverสายในตามที่ระบุแน่นอนวิธีการที่เหมาะสมที่จะไปหากควบคุมจะถูกนำเสนอผ่านviewWillDisappear pushViewControllerถ้าคุณใส่deallocแทนก็deallocจะไม่ถูกเรียก - จากประสบการณ์ของฉันอย่างน้อย ...
Christopher King

38

เนื่องจาก iOS 9 จึงไม่จำเป็นต้องลบผู้สังเกตการณ์อีกต่อไป

ใน OS X 10.11 และ iOS 9.0 NSNotificationCenter และ NSDistributedNotificationCenter จะไม่ส่งการแจ้งเตือนไปยังผู้สังเกตการณ์ที่ลงทะเบียนซึ่งอาจถูกยกเลิกการจัดสรรอีกต่อไป

https://developer.apple.com/library/mac/releasenotes/Foundation/RN-Foundation/index.html#10_11NotificationCenter


2
อาจเป็นเพราะพวกเขาจะไม่ส่งข้อความถึงผู้สังเกตการณ์ แต่ฉันเชื่อว่าพวกเขาจะให้ข้อมูลอ้างอิงที่ชัดเจนถึงพวกเขาอย่างที่ฉันเข้าใจ ในกรณีนี้ผู้สังเกตการณ์ทั้งหมดจะอยู่ในความทรงจำและเกิดการรั่วไหล แก้ไขฉันถ้าฉันผิด
เฟอร์

6
เอกสารที่เชื่อมโยงจะให้รายละเอียดเกี่ยวกับเรื่องนั้น TL; DR: เป็นการอ้างอิงที่อ่อนแอ
Sebastian

แต่แน่นอนว่ายังคงจำเป็นในกรณีที่คุณเก็บวัตถุที่อ้างอิงไว้รอบ ๆ และไม่ต้องการฟังการแจ้งเตือนอีกต่อไป
TheEye

25

หากสังเกตจะถูกเพิ่มไปยังตัวควบคุมมุมมองผมขอแนะนำให้เพิ่มในและถอดมันออกมาในviewWillAppearviewWillDisappear


ฉันอยากรู้ @RickiG: ทำไมคุณถึงแนะนำให้ใช้viewWillAppearและviewWillDisappearสำหรับ viewControllers
Isaac Overacker

2
@IsaacOveracker เหตุผลสองสามประการ: โค้ดการตั้งค่าของคุณ (เช่น loadView และ viewDidLoad) อาจทำให้การแจ้งเตือนเริ่มทำงานและคอนโทรลเลอร์ของคุณจำเป็นต้องสะท้อนสิ่งนั้นก่อนที่จะแสดง หากคุณทำเช่นนี้มีประโยชน์เล็กน้อย ในขณะที่คุณตัดสินใจ "ออก" ตัวควบคุมที่คุณไม่สนใจเกี่ยวกับการแจ้งเตือนและพวกมันจะไม่ทำให้คุณใช้ตรรกะในขณะที่ตัวควบคุมกำลังถูกผลักออกจากหน้าจอเป็นต้นมีกรณีพิเศษที่คอนโทรลเลอร์ควรได้รับการแจ้งเตือนเมื่อมี นอกจอฉันเดาว่าคุณทำไม่ได้ แต่เหตุการณ์เช่นนั้นน่าจะอยู่ในโมเดลของคุณ
RickiG

1
@IsaacOveracker ด้วย ARC มันจะแปลกที่จะใช้ dealloc เพื่อยกเลิกการสมัครรับการแจ้งเตือน
RickiG

4
จากสิ่งที่ฉันได้ลองใช้ iOS7 นี่เป็นวิธีที่ดีที่สุดในการลงทะเบียน / ลบผู้สังเกตการณ์เมื่อทำงานกับ UIViewControllers สิ่งเดียวที่จับได้คือในหลาย ๆ กรณีคุณไม่ต้องการให้ผู้สังเกตการณ์ถูกลบออกเมื่อใช้ UINavigationController และผลัก UIViewController อื่นไปที่สแต็ก วิธีแก้ไข: คุณสามารถตรวจสอบได้ว่า VC ถูกเปิดใน viewWillDisappear หรือไม่โดยการเรียก [self isBeingDismissed]
lekksi

การเปิดตัวควบคุมมุมมองจากตัวควบคุมการนำทางอาจไม่ทำให้deallocถูกเรียกทันที การกลับไปที่ตัวควบคุมมุมมองอาจทำให้เกิดการแจ้งเตือนหลายครั้งหากมีการเพิ่มผู้สังเกตการณ์ในคำสั่งเริ่มต้น
Jonathan Lin

20
-(void) dealloc {
      [[NSNotificationCenter defaultCenter] removeObserver:self];
      [super dealloc];
}

4
ฉันจะเปลี่ยนลำดับของคำแนะนำเหล่านี้เป็นรอบ ๆ ... การใช้selfafter [super dealloc]ทำให้ฉันกังวล ... (แม้ว่าผู้รับไม่น่าจะหักล้างตัวชี้ แต่อย่างใดคุณไม่มีทางรู้หรอกว่าพวกเขาใช้งานอย่างไรNSNotificationCenter)
เดิร์ก

หืม มันได้ผลสำหรับฉัน คุณสังเกตเห็นพฤติกรรมที่ผิดปกติหรือไม่?
Legolas

1
Dirk พูดถูก - นี่ไม่ถูกต้อง [super dealloc]ต้องเป็นคำสั่งสุดท้ายของdeallocวิธีการของคุณเสมอ มันทำลายวัตถุของคุณ หลังจากทำงานคุณจะไม่มีที่ถูกต้องselfอีกต่อไป / cc
@Dirk

38
หากใช้ ARC บน iOS 5+ ฉันคิดว่า[super dealloc]ไม่จำเป็นอีกต่อไป
pixelfreak

3
@pixelfreak แรงกว่าไม่อนุญาตภายใต้ ARC ให้เรียก [super
dealloc


7

ในการใช้ deinit อย่างรวดเร็วเนื่องจาก dealloc ไม่พร้อมใช้งาน:

deinit {
    ...
}

เอกสาร Swift:

deinitializer ถูกเรียกใช้ทันทีก่อนที่จะเลิกจัดสรรอินสแตนซ์ของคลาส คุณเขียน deinitializers ด้วยคีย์เวิร์ด deinit คล้ายกับการเขียน intializers ด้วยคีย์เวิร์ด init Deinitializers มีให้บริการในประเภทคลาสเท่านั้น

โดยทั่วไปคุณไม่จำเป็นต้องล้างข้อมูลด้วยตนเองเมื่อยกเลิกการจัดสรรอินสแตนซ์ของคุณ อย่างไรก็ตามเมื่อคุณทำงานกับทรัพยากรของคุณเองคุณอาจต้องดำเนินการล้างข้อมูลเพิ่มเติมด้วยตัวคุณเอง ตัวอย่างเช่นหากคุณสร้างคลาสแบบกำหนดเองเพื่อเปิดไฟล์และเขียนข้อมูลบางอย่างลงไปคุณอาจต้องปิดไฟล์ก่อนที่จะยกเลิกการจัดสรรอินสแตนซ์ของคลาส


5

* แก้ไข: คำแนะนำนี้ใช้กับ iOS <= 5 (แม้ว่าคุณควรจะเพิ่มviewWillAppearและลบในนั้นviewWillDisappearก็ตาม - อย่างไรก็ตามคำแนะนำจะมีผลบังคับใช้หากคุณเพิ่มผู้สังเกตการณ์ด้วยเหตุผลบางประการviewDidLoad)

หากคุณได้เพิ่มผู้สังเกตการณ์เข้าไปviewDidLoadคุณควรลบออกทั้งในdeallocและviewDidUnload. มิฉะนั้นคุณจะต้องเพิ่มสองครั้งเมื่อviewDidLoadถูกเรียกหลังจากนั้นviewDidUnload(สิ่งนี้จะเกิดขึ้นหลังจากคำเตือนหน่วยความจำ) สิ่งนี้ไม่จำเป็นใน iOS 6 ที่viewDidUnloadเลิกใช้งานและจะไม่ถูกเรียกใช้ (เนื่องจากมุมมองจะไม่ถูกยกเลิกการโหลดโดยอัตโนมัติอีกต่อไป)


2
ยินดีต้อนรับสู่ StackOverflow โปรดตรวจสอบคำถามที่พบบ่อยของ MarkDown (ไอคอนเครื่องหมายคำถามถัดจากช่องแก้ไขคำถาม / คำตอบ) การใช้ Markdwon จะช่วยปรับปรุงการใช้งานคำตอบของคุณ
marko

5

ในความคิดของฉันรหัสต่อไปนี้ไม่สมเหตุสมผลในARC :

- (void)dealloc
{
      [[NSNotificationCenter defaultCenter] removeObserver:self];
      [super dealloc];
}

ในiOS 6ยังไม่มีเหตุผลที่จะลบผู้สังเกตการณ์ออกviewDidUnloadเนื่องจากตอนนี้เลิกใช้งานแล้ว

viewDidDisappearเพื่อสรุปฉันมักจะทำมันใน อย่างไรก็ตามขึ้นอยู่กับความต้องการของคุณเช่นกันเช่นเดียวกับที่ @Dirk กล่าว


ผู้คนจำนวนมากยังคงเขียนโค้ดสำหรับ iOS เวอร์ชันเก่ากว่า iOS6 .... :-)
lnafziger

ใน ARC คุณสามารถใช้รหัสนี้ได้ แต่ไม่มีบรรทัด [super dealloc] สามารถดูข้อมูลเพิ่มเติมได้ที่นี่: developer.apple.com/library/ios/#releasenotes/ObjectiveC/…
Alex

1
จะเกิดอะไรขึ้นถ้าคุณมี NSObject เป็นผู้สังเกตการณ์การแจ้งเตือน? คุณจะใช้ dealloc ในกรณีนี้หรือไม่?
qix

4

ฉันคิดว่าฉันพบคำตอบที่เชื่อถือได้ ! ฉันต้องเพราะคำตอบข้างต้นคลุมเครือและดูเหมือนขัดแย้งกัน ฉันดูตำราและคู่มือการเขียนโปรแกรม

ครั้งแรกที่รูปแบบของaddObserver:ในviewWillAppear:และremoveObserver:ในviewWillDisappear:ไม่ทำงานสำหรับฉัน (ผมทดสอบ) เพราะผมกำลังโพสต์แจ้งเตือนในตัวควบคุมมุมมองเด็กที่จะรันโค้ดในการควบคุมมุมมองของผู้ปกครอง ฉันจะใช้รูปแบบนี้ก็ต่อเมื่อฉันโพสต์และฟังการแจ้งเตือนภายในตัวควบคุมมุมมองเดียวกัน

คำตอบที่ฉันจะพึ่งพามากที่สุดฉันพบในการเขียนโปรแกรม iOS: Big Nerd Ranch Guide 4th ฉันเชื่อใจพวก BNR เพราะพวกเขามีศูนย์ฝึกอบรม iOS และพวกเขาไม่ได้แค่เขียนตำราอาหารอื่น อาจเป็นไปเพื่อประโยชน์สูงสุดของความถูกต้อง

BNR ตัวอย่างที่หนึ่ง: addObserver:ในinit:, removeObserver:ในdealloc:

BNR ตัวอย่างที่สอง: addObserver:in awakeFromNib:, removeObserver:indealloc:

…เมื่อนำผู้สังเกตการณ์ออกจากที่dealloc:พวกเขาไม่ได้ใช้[super dealloc];

หวังว่านี่จะช่วยคนต่อไป ...

ฉันกำลังอัปเดตโพสต์นี้เนื่องจากตอนนี้ Apple ได้เลิกใช้ Storyboards ไปเกือบหมดแล้วดังนั้นสิ่งที่กล่าวมาข้างต้นอาจใช้ไม่ได้กับทุกสถานการณ์ สิ่งที่สำคัญ (และเหตุผลที่ฉันเพิ่มโพสต์นี้ในตอนแรก) คือให้ความสนใจหากคุณviewWillDisappear:ถูกเรียก ไม่ใช่สำหรับฉันเมื่อแอปพลิเคชันเข้าสู่พื้นหลัง


เป็นการยากที่จะบอกว่าสิ่งนี้ถูกต้องหรือไม่เนื่องจากบริบทมีความสำคัญ มีการกล่าวถึงสองสามครั้งแล้ว แต่ dealloc ไม่ค่อยมีเหตุผลในบริบท ARC (ซึ่งเป็นบริบทเดียวในตอนนี้) นอกจากนี้ยังไม่สามารถคาดเดาได้เมื่อเรียกใช้ dealloc - viewWillDisappear นั้นควบคุมได้ง่ายกว่า หมายเหตุด้านข้าง: หากบุตรหลานของคุณต้องการสื่อสารบางอย่างกับผู้ปกครองรูปแบบผู้รับมอบสิทธิ์ดูเหมือนจะเป็นทางเลือกที่ดีกว่า
RickiG

2

คำตอบที่ยอมรับนั้นไม่ปลอดภัยและอาจทำให้หน่วยความจำรั่วได้ โปรดอย่าลงทะเบียนใน dealloc แต่ก็ยกเลิกการลงทะเบียนใน viewWillDisappear ด้วย (แน่นอนว่าถ้าคุณลงทะเบียนใน viewWillAppear) .... นั่นคือสิ่งที่ฉันทำไปตลอดเวลาและมันได้ผลดีมาก! :)


1
ฉันเห็นด้วยกับคำตอบนี้ ฉันพบคำเตือนและการรั่วไหลของหน่วยความจำซึ่งนำไปสู่การขัดข้องหลังจากใช้งานแอพอย่างเข้มข้นหากฉันไม่ลบผู้สังเกตการณ์ใน viewWillDisappear
SarpErdag

2

สิ่งสำคัญคือต้องสังเกตด้วยว่าviewWillDisappearจะถูกเรียกด้วยเมื่อตัวควบคุมมุมมองนำเสนอ UIView ใหม่ ผู้รับมอบสิทธิ์นี้เพียงระบุว่ามุมมองหลักของตัวควบคุมมุมมองไม่สามารถมองเห็นได้บนจอแสดงผล

ในกรณีนี้การยกเลิกการจัดสรรการแจ้งเตือนในviewWillDisappearอาจไม่สะดวกหากเราใช้การแจ้งเตือนเพื่อให้ UIview สื่อสารกับตัวควบคุมมุมมองหลัก

ในการแก้ปัญหาฉันมักจะลบผู้สังเกตการณ์ด้วยหนึ่งในสองวิธีนี้:

- (void)viewWillDisappear:(BOOL)animated {
    NSLog(@"viewController will disappear");
    if ([self isBeingDismissed]) {
        NSLog(@"viewController is being dismissed");
        [[NSNotificationCenter defaultCenter] removeObserver:self name:@"actionCompleted" object:nil];
    }
}

-(void)dealloc {
    NSLog(@"viewController is being deallocated");
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"actionCompleted" object:nil];
}

ด้วยเหตุผลที่คล้ายกันเมื่อฉันออกการแจ้งเตือนในครั้งแรกฉันจำเป็นต้องคำนึงถึงข้อเท็จจริงที่ว่าเมื่อใดก็ตามที่มีมุมมองที่ปรากฏเหนือตัวควบคุมviewWillAppearเมธอดจะเริ่มทำงาน สิ่งนี้จะสร้างสำเนาการแจ้งเตือนเดียวกันหลายชุด เนื่องจากไม่มีวิธีตรวจสอบว่าการแจ้งเตือนเปิดใช้งานอยู่แล้วหรือไม่ฉันจึงแก้ไขปัญหาโดยการลบการแจ้งเตือนก่อนเพิ่ม:

- (void)viewWillAppear:(BOOL)animated {
    NSLog(@"viewController will appear");
    // Add observers
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"imageGenerated" object:nil]; // This is added to avoid duplicate notifications when the view is presented again
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receivedImageFromCameraOrPhotolibraryMethodOnListener:) name:@"actionCompleted" object:nil];

}

-1

SWIFT 3

มีสองกรณีในการใช้การแจ้งเตือน: - จำเป็นเฉพาะเมื่อตัวควบคุมมุมมองอยู่บนหน้าจอ - จำเป็นเสมอแม้ว่าผู้ใช้จะเปิดหน้าจออื่นในปัจจุบันก็ตาม

สำหรับกรณีแรกสถานที่ที่ถูกต้องในการเพิ่มและลบผู้สังเกตการณ์คือ:

/// Add observers
///
/// - Parameter animated: the animation flag
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    NotificationCenter.default.addObserver(...)
}

/// Remove observers
///
/// - Parameter animated: the animation flag
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    NotificationCenter.default.removeObserver(self)
}

สำหรับกรณีที่สองวิธีที่ถูกต้องคือ:

/// Add observers
override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(...)
}

/// Remove observers
///
/// - Parameter animated: the animation flag
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    if self.isBeingDismissed // remove only when view controller is removed disappear forever
    || !(self.navigationController?.viewControllers.contains(self) ?? true) {
        NotificationCenter.default.removeObserver(self)
    }
}

และไม่เคยใส่removeObserverในdeinit{ ... }- มันผิดพลาด!


-1
override func viewDidLoad() {   //add observer
  super.viewDidLoad()
  NotificationCenter.default.addObserver(self, selector:#selector(Yourclassname.method), name: NSNotification.Name(rawValue: "NotificationIdentifier"), object: nil)
}

override func viewWillDisappear(_ animated: Bool) {    //remove observer
    super.viewWillDisappear(true)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "NotificationIdentifier"), object: nil)
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.