ViewDidAppear ไม่ได้ถูกเรียกเมื่อเปิดแอปจากพื้นหลัง


175

ฉันมีตัวควบคุมมุมมองซึ่งค่าของฉันคือ 0 (ฉลาก) และเมื่อฉันเปิดตัวควบคุมมุมมองนั้นจากอีกตัวหนึ่งViewControllerฉันได้viewDidAppearตั้งค่าเป็น 20 บนฉลาก มันทำงานได้ดี แต่เมื่อผมปิด app ของฉันและมากกว่าอีกครั้งฉันเปิด app ของฉัน แต่ค่าไม่เปลี่ยนแปลงเพราะviewDidLoad, viewDidAppearและviewWillAppearไม่มีอะไรที่ได้รับการเรียก ฉันจะโทรหาได้อย่างไรเมื่อเปิดแอพ ฉันต้องทำอะไรจากapplicationDidBecomeActiveหรือไม่


คุณสามารถโพสต์การแจ้งเตือนในท้องถิ่นเมื่อแอปพลิเคชันเริ่มทำงานและเพิ่มตัวควบคุมมุมมองของคุณเป็นผู้สังเกตการณ์และอัปเดตค่า
Adil Soomro

คำตอบ:


314

ฉันสงสัยเกี่ยวกับลำดับเหตุการณ์ที่แน่นอนฉันใช้แอพดังต่อไปนี้: (@Zohaib คุณสามารถใช้รหัส NSNotificationCenter ด้านล่างเพื่อตอบคำถามของคุณ)

// AppDelegate.m

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    NSLog(@"app will enter foreground");
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    NSLog(@"app did become active");
}

// ViewController.m

- (void)viewDidLoad
{
    [super viewDidLoad];
    NSLog(@"view did load");

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
}

- (void)appDidBecomeActive:(NSNotification *)notification {
    NSLog(@"did become active notification");
}

- (void)appWillEnterForeground:(NSNotification *)notification {
    NSLog(@"will enter foreground notification");
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    NSLog(@"view will appear");
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    NSLog(@"view did appear");
}

เมื่อเปิดตัวเอาต์พุตจะมีลักษณะดังนี้:

2013-04-07 09:31:06.505 myapp[15459:11303] view did load
2013-04-07 09:31:06.507 myapp[15459:11303] view will appear
2013-04-07 09:31:06.511 myapp[15459:11303] app did become active
2013-04-07 09:31:06.512 myapp[15459:11303] did become active notification
2013-04-07 09:31:06.517 myapp[15459:11303] view did appear

ป้อนพื้นหลังจากนั้นป้อนพื้นหน้าอีกครั้ง:

2013-04-07 09:32:05.923 myapp[15459:11303] app will enter foreground
2013-04-07 09:32:05.924 myapp[15459:11303] will enter foreground notification
2013-04-07 09:32:05.925 myapp[15459:11303] app did become active
2013-04-07 09:32:05.926 myapp[15459:11303] did become active notification

1
Danh คุณทำการแมป UIApplicationWillEnterForegroundNotification ให้กับ appDidEnterForeground: นั่นไม่ใช่ความเข้าใจผิดหรือเปล่า? สังเกตว่า "จะ" และ "ทำ" เป็นความตั้งใจหรือไม่?
Lubiluk

@Lubiluk - ไม่ได้ตั้งใจ ฉันจะแก้ไข จับดี.
danh

4
นี่เป็นคำตอบที่มีประโยชน์มาก ฉันทำรุ่นสวิฟท์มันนี่
Suragch

การสาธิตที่สมบูรณ์แบบของโหมดพื้นหลัง!
Marcelo dos Santos

ลำดับเหตุการณ์เมื่อคุณแตะสองครั้งที่ปุ่มโฮมแล้วปิดแอพ
Amjad Husseini

134

ใช้ Objective-C

คุณควรจะลงทะเบียนUIApplicationWillEnterForegroundNotificationในของคุณViewController's viewDidLoadวิธีการและเมื่อใดก็ตามที่แอปจะกลับมาจากพื้นหลังที่คุณสามารถทำสิ่งที่คุณต้องการจะทำในวิธีการลงทะเบียนสำหรับการแจ้งเตือน ViewController' viewWillAppear ' หรือviewDidAppearจะไม่ถูกเรียกเมื่อแอปกลับมาจากพื้นหลังเป็นพื้นหน้า

-(void)viewDidLoad{

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doYourStuff)

  name:UIApplicationWillEnterForegroundNotification object:nil];
}

-(void)doYourStuff{

   // do whatever you want to do when app comes back from background.
}

อย่าลืมยกเลิกการลงทะเบียนการแจ้งเตือนที่คุณลงทะเบียนไว้

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

หมายเหตุหากคุณลงทะเบียนviewControllerสำหรับUIApplicationDidBecomeActiveNotificationวิธีการของคุณจะถูกเรียกทุกครั้งที่แอปของคุณเปิดใช้งานไม่แนะนำให้ลงทะเบียนviewControllerสำหรับการแจ้งเตือนนี้

ใช้สวิฟท์

สำหรับการเพิ่มผู้สังเกตการณ์คุณสามารถใช้รหัสต่อไปนี้

 override func viewDidLoad() {
    super.viewDidLoad()

     NotificationCenter.default.addObserver(self, selector: "doYourStuff", name: UIApplication.willEnterForegroundNotification, object: nil)
 }

 func doYourStuff(){
     // your code
 }

ในการลบผู้สังเกตการณ์คุณสามารถใช้ฟังก์ชัน deinit ของ swift

deinit {
    NotificationCenter.default.removeObserver(self)
}

4
ใช่มันเป็น :) บางครั้งมันก็เป็นเรื่องยากที่จะหาคำตอบ :)
nsgulliver

@nsgulliver ฉันต้องเรียกยกเลิกการลงทะเบียนการแจ้งเตือนด้วยตนเอง - (เป็นโมฆะ) dealloc {[[NSNotificationCenter defaultCenter] removeObserver: self]; }. แอพจะทำเพื่อฉันหรือไม่
ios

43

รุ่น Swift 3.0 ++

ในของคุณviewDidLoadลงทะเบียนที่ศูนย์การแจ้งเตือนเพื่อฟังสิ่งนี้เปิดจากการกระทำเบื้องหลัง

NotificationCenter.default.addObserver(self, selector:#selector(doSomething), name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil)
        

จากนั้นเพิ่มฟังก์ชันนี้และดำเนินการที่จำเป็น

func doSomething(){
    //...
}

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

deinit {
    NotificationCenter.default.removeObserver(self)
}

ทางออกที่ง่ายและตรงไปตรงมาเพื่อจัดการการแจ้งเตือนภายใน VC +1
Mo Zaatar

ไม่อยากเชื่อเลยว่าคำตอบที่ดีนี้พลาดไปกับคำถาม SO ที่คล้ายกัน / ซ้ำ ๆ กันมากมาย
Hugo Allexis Cardona

11

สวิฟท์ 4.2 รุ่น

ลงทะเบียนกับ NotificationCenter viewDidLoadเพื่อรับการแจ้งเตือนเมื่อแอปกลับมาจากพื้นหลัง

NotificationCenter.default.addObserver(self, selector: #selector(doSomething), name: UIApplication.willEnterForegroundNotification, object: nil)

ใช้วิธีการที่ควรจะเรียกว่า

@objc private func doSomething() {
    // Do whatever you want, for example update your view.
}

คุณสามารถลบผู้สังเกตการณ์เมื่อViewControllerถูกทำลาย ต้องการเพียงด้านล่าง iOS9 และ macOS 10.11

deinit {
    NotificationCenter.default.removeObserver(self)
}

1
FYI ฉันค่อนข้างแน่ใจว่าคุณไม่จำเป็นต้องลบผู้สังเกตการณ์อีกต่อไปในวันนี้ ...
Fattie

3

เพียงแค่ให้ตัวควบคุมมุมมองของคุณลงทะเบียนสำหรับการUIApplicationWillEnterForegroundNotificationแจ้งเตือนและตอบสนองตามนั้น


ฉันจะทำอย่างไร ฉันเรียกว่า viewController ของฉันใน applicationDidBecomeActive แต่ มันซ้อนทับ viewController หรือมันดีที่จะทำอย่างนั้น?
Zohaib

2
อย่าเรียก viewController ของคุณใน applicationDidBecomeActive (ซึ่งมันผิดอยู่ดีเพราะมันถูกเรียกหลายครั้ง) ลงทะเบียนเพื่อรับการแจ้งเตือนตามที่คุณviewDidLoadแนะนำ @nsgulliver คุณviewDidAppearจะโทรติดต่อdoYourStuffเพื่อตั้งค่าป้ายกำกับของคุณด้วยค่าที่ต้องการ
andreagiavatto

3

ฉันคิดว่าการลงทะเบียน UIApplicationWillEnterForegroundNotification นั้นมีความเสี่ยงเนื่องจากคุณอาจจบลงด้วยคอนโทรลเลอร์มากกว่าหนึ่งตัวที่ตอบสนองต่อการแจ้งเตือนนั้น ไม่มีอะไรรับประกันได้ว่าคอนโทรลเลอร์เหล่านี้จะยังคงมองเห็นได้เมื่อได้รับการแจ้งเตือน

นี่คือสิ่งที่ฉันทำ: ฉันบังคับให้เรียก viewDidAppear บนคอนโทรลเลอร์ที่แอ็คทีฟโดยตรงจากวิธีมอบอำนาจ didBecomeActive ของแอพโดยตรง:

เพิ่มรหัสด้านล่างเพื่อ - (void)applicationDidBecomeActive:(UIApplication *)application

UIViewController *activeController = window.rootViewController;
if ([activeController isKindOfClass:[UINavigationController class]]) {
    activeController = [(UINavigationController*)window.rootViewController topViewController];
}
[activeController viewDidAppear:NO];

7
มีการรับประกันว่าคอนโทรลเลอร์ยกเลิกการลงทะเบียน (ตามที่ควร) สำหรับ UIApplicationWillEnterForegroundNotification ใน viewWillDisappear แทนที่จะเป็น dealloc โทร viewDidAppear ดูเหมือนแฮ็คกับฉันอย่างชัดเจนมันจะแบ่งซีแมนทิกส์ (มุมมองส่วนตัว) และอาจทำให้ผู้คนสับสน (จากประสบการณ์)
joakim

3

ลองเพิ่มใน AppDelegate applicationWillEnterForeground

func applicationWillEnterForeground(_ application: UIApplication) {        
    // makes viewWillAppear run
    self.window?.rootViewController?.beginAppearanceTransition(true, animated: false)
    self.window?.rootViewController?.endAppearanceTransition()
}

2

ตามเอกสารของ Apple:

(void)beginAppearanceTransition:(BOOL)isAppearing animated:(BOOL)animated;

คำอธิบาย:
บอกว่าตัวควบคุมลูกมีลักษณะที่จะเปลี่ยนแปลง หากคุณกำลังดำเนินการควบคุมภาชนะที่กำหนดเองใช้วิธีการนี้จะบอกเด็กว่ามุมมองของมันเป็นเรื่องเกี่ยวกับการปรากฏขึ้นหรือหายไป อย่าเรียกviewWillAppear:, viewWillDisappear:, viewDidAppear:หรือviewDidDisappear:โดยตรง

(void)endAppearanceTransition;

รายละเอียด:

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

รหัสตัวอย่าง:

(void)applicationDidEnterBackground:(UIApplication *)application
{

    [self.window.rootViewController beginAppearanceTransition: NO animated: NO];  // I commented this line

    [self.window.rootViewController endAppearanceTransition]; // I commented this line

}

คำถาม: ฉันจะแก้ไขอย่างไร

ตอบ : ฉันพบชิ้นส่วนนี้ในแอปพลิเคชัน บรรทัดนี้ทำให้แอปของฉันไม่รับการแจ้งเตือน ViewWillAppear ใด ๆ เมื่อตอนที่ผมแสดงความคิดเห็นเส้นเหล่านี้ก็ปรับการทำงาน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.