การจัดการแอพพลิเคชั่นidBecomeActive -“ ตัวควบคุมมุมมองจะตอบสนองอย่างไรกับแอปที่กำลังใช้งานอยู่”


179

ฉันมีUIApplicationDelegateโปรโตคอลในคลาส AppDelegate.m หลักของฉันพร้อมด้วยapplicationDidBecomeActiveวิธีการที่กำหนด

ฉันต้องการเรียกเมธอดเมื่อแอปพลิเคชันส่งคืนจากพื้นหลัง แต่เมธอดนั้นอยู่ในตัวควบคุมมุมมองอื่น ฉันจะตรวจสอบว่าตัวควบคุมมุมมองใดที่กำลังแสดงอยู่ในapplicationDidBecomeActiveวิธีการแล้วโทรไปยังวิธีการภายในตัวควบคุมนั้นได้อย่างไร

คำตอบ:


304

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

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(someMethod:)
                                             name:UIApplicationDidBecomeActiveNotification object:nil];

อย่าลืมล้างตัวเองด้วย! อย่าลืมลบตัวเองในฐานะผู้สังเกตการณ์เมื่อความคิดเห็นของคุณหายไป:

[[NSNotificationCenter defaultCenter] removeObserver:self 
                                                name:UIApplicationDidBecomeActiveNotification
                                              object:nil];

ข้อมูลเพิ่มเติมเกี่ยวกับการแจ้งเตือนศูนย์


ยอดเยี่ยม NSNotificationCenterไม่ได้คิดว่าการใช้ ขอบคุณ!
Calvin

3
เพียงพิมพ์ผิดในบรรทัดของรหัส (ไม่มี 'ชื่อ'): [[NSNotificationCenter defaultCenter] addObserver: ตัวเลือกด้วยตนเอง: @selector (someMethod :) ชื่อ: UIApplicationDidBecomeActiveNotification วัตถุ: ไม่มี]
Johnus

3
ในการเพิ่มคำตอบของ Reed วิธีการที่เรียกว่า (ในตัวอย่างนี้คือ someMethod) จำเป็นต้องยอมรับพารามิเตอร์ NSNotification ดังนั้นลายเซ็นวิธีการสำหรับบางวิธีจะเป็น - (เป็นโมฆะ) someMethod: (NSNotification *) การแจ้งเตือน {// ทำบางสิ่งที่นี่}
Aaron

2
@Aaron มันสามารถ แต่มันไม่ได้เป็นความต้องการ แม้ว่าจะมีความเข้าใจที่ดี ขอบคุณ!
Reed Olsen

Fantastic! ช่างเป็นวิธีที่ยอดเยี่ยมในการทำให้โมฆะ / สร้าง NSTimer อินสแตนซ์ที่เกิดขึ้นในมุมมองตัวควบคุม / วัตถุอื่น ๆ ที่รับผิดชอบ NSTimers เหล่านั้น รักมัน!
idStar

68

สวิฟต์ 3, 4 เทียบเท่า:

เพิ่มผู้สังเกตการณ์

NotificationCenter.default.addObserver(self,
    selector: #selector(applicationDidBecomeActive),
    name: .UIApplicationDidBecomeActive, // UIApplication.didBecomeActiveNotification for swift 4.2+
    object: nil)

ลบผู้สังเกตการณ์

NotificationCenter.default.removeObserver(self,
    name: .UIApplicationDidBecomeActive, // UIApplication.didBecomeActiveNotification for swift 4.2+
    object: nil)

โทรกลับ

@objc func applicationDidBecomeActive() {
    // handle event
}

2
ฉันจะเรียกสิ่งนี้ได้ที่ไหน

1
@ user8169082 คุณเพิ่มผู้สังเกตการณ์ทุกที่ที่คุณต้องการเริ่มรับการแจ้งเตือน คุณสามารถเพิ่มลงในviewDidLoadหรือviewWillAppear:animatedตัวอย่าง และคุณสามารถเอาผู้สังเกตการณ์เมื่อคุณไม่มีการแจ้งเตือนความจำเป็นอีกต่อไปหรือเมื่อผู้สังเกตการณ์อินสแตนซ์ของคุณเป็นไปได้ใน deallocated วิธี deinit
igrek

2
รวดเร็ว 4.2 ฉันใช้: NotificationCenter.default.addObserver (ตัวเอง, เลือก: #selector (applicationDidBecomeActive (การแจ้งเตือน :)) ชื่อ: UIApplication.didBecomeActiveNotification วัตถุ: ไม่มี)
ไบรอัน

16

สวิฟท์ 2 เทียบเท่า :

let notificationCenter = NSNotificationCenter.defaultCenter()

// Add observer:
notificationCenter.addObserver(self,
  selector:Selector("applicationWillResignActiveNotification"),
  name:UIApplicationWillResignActiveNotification,
  object:nil)

// Remove observer:
notificationCenter.removeObserver(self,
  name:UIApplicationWillResignActiveNotification,
  object:nil)

// Remove all observer for all notifications:
notificationCenter.removeObserver(self)

// Callback:
func applicationWillResignActiveNotification() {
  // Handle application will resign notification event.
}

สถานที่ที่ดีที่สุดที่จะใส่removeObserverใน Swift: deinitวิธี
Enrico Susatyo

โดยทั่วไปแล้วการเข้าถึงตัวเองใน deinit ไม่แนะนำ; ณ จุดนี้ตัวเองอยู่ในระหว่างการจัดสรรอย่างเต็มที่และถูกจัดสรรคืน
Zorayr

1
คุณจะลบผู้สังเกตการณ์ที่ไหน
Enrico Susatyo

2
@EnricoSusatyo คุณสามารถเพิกเฉยได้เพราะมันไม่ถูกต้อง การยกเลิกการ deinit นั้นใช้ได้: "เนื่องจากอินสแตนซ์ไม่ได้ถูกจัดสรรคืนจนกระทั่งหลังจากที่ deinitializer ถูกเรียกใช้ deinitializer สามารถเข้าถึงคุณสมบัติทั้งหมดของอินสแตนซ์ที่ถูกเรียกใช้และสามารถปรับเปลี่ยนพฤติกรรมตามคุณสมบัติเหล่านั้น (เช่นการค้นหาชื่อของ ไฟล์ที่จะต้องปิด) " การโทร deinit ไม่เป็นไร
Dan Rosenstark

7

สวิฟท์ 4.2

เพิ่มผู้สังเกตการณ์ -

NotificationCenter.default.addObserver(self, selector: #selector(handleEvent), name: UIApplication.didBecomeActiveNotification, object: nil)

ลบผู้สังเกตการณ์ -

NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil)

จัดการเหตุการณ์ -

@objc func handleEvent() {
}

5

ด้วย Swift 4 Apple แนะนำผ่านคำเตือนคอมไพเลอร์ใหม่ว่าเราหลีกเลี่ยงการใช้#selectorในสถานการณ์นี้ ต่อไปนี้เป็นวิธีที่ปลอดภัยกว่ามากในการทำสิ่งนี้ให้สำเร็จ:

ก่อนอื่นให้สร้าง var สันหลังยาวที่การแจ้งเตือนสามารถใช้งานได้:

lazy var didBecomeActive: (Notification) -> Void = { [weak self] _ in
    // Do stuff
} 

หากคุณจำเป็นต้องมีการแจ้งเตือนที่เกิดขึ้นจริงจะรวมเพียงแทนที่ด้วย_notification

ต่อไปเราตั้งค่าการแจ้งเตือนเพื่อดูว่าแอปพลิเคชันทำงานอยู่หรือไม่

func setupObserver() {
    _ = NotificationCenter.default.addObserver(forName: .UIApplicationDidBecomeActive,
                                               object: nil,
                                               queue:.main,
                                               using: didBecomeActive)
}

การเปลี่ยนแปลงครั้งใหญ่ที่นี่ก็คือแทนที่จะเรียก a #selectorตอนนี้เราเรียก var ที่สร้างไว้ด้านบน สิ่งนี้สามารถกำจัดสถานการณ์ที่คุณได้รับตัวเลือกที่ไม่ถูกต้องเกิดปัญหา

ในที่สุดเราก็ลบผู้สังเกตการณ์

func removeObserver() {
    NotificationCenter.default.removeObserver(self, name: .UIApplicationDidBecomeActive, object: nil)
}

1
#selectorสามารถเรียกใช้เมธอดที่ประกาศเป็น@objcแอตทริบิวต์ใน Swift 4
AnBisw

1
มันไม่ถูกต้องที่จะใช้removeObserver(selfเพราะตนเองไม่ได้รับมอบหมายเมื่อเพิ่มผู้สังเกตการณ์ คุณควรlet observer = NotificationCenter.default.addObserverแล้วremoveObserver(observer
ยัน Kalbaska

ขอบคุณ @CodeBender ผมไม่ทราบว่าการทำงานเลยและมัน (สุดท้าย) @objcเอา อย่างไรก็ตามเมื่อฉันลองฉันจะได้รับคำเตือนในคอนโซล (Xcode 11.3.1 (11C504), Swift 13.3): ไม่สามารถจบ BackgroundTask: ไม่มีงานพื้นหลังที่มีตัวระบุ แม้ว่าฉันจะบันทึกผู้สังเกตการณ์ในตัวแปรเป็น NSObjectProtocol
palme

ไม่เป็นไรฉันยังได้รับคำเตือนถ้าฉันใช้@objcตัวแปร
palme

3

สวิฟท์ 5

fileprivate  func addObservers() {
      NotificationCenter.default.addObserver(self,
                                             selector: #selector(applicationDidBecomeActive),
                                             name: UIApplication.didBecomeActiveNotification,
                                             object: nil)
    }

fileprivate  func removeObservers() {
        NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil)
    }

@objc fileprivate func applicationDidBecomeActive() {
// here do your work
    }

0

วิธีการรวม:

import Combine

var cancellables = Set<AnyCancellable>()
NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)
    .sink { notification in
            // do stuff
    }.store(in: &cancellables)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.