ViewDidAppear tidak dipanggil saat membuka aplikasi dari latar belakang

175

Saya memiliki View Controller di mana nilai saya adalah 0 (label) dan ketika saya membuka View Controller itu dari yang lain ViewControllersaya telah menetapkan viewDidAppearuntuk menetapkan nilai 20 pada label. Ini berfungsi dengan baik tetapi ketika saya menutup aplikasi saya dan lagi saya membuka aplikasi saya tetapi nilainya tidak berubah karena viewDidLoad, viewDidAppeardan viewWillAppeartidak ada yang dipanggil. Bagaimana saya bisa menelepon ketika saya membuka aplikasi saya. Apakah saya harus melakukan sesuatu applicationDidBecomeActive?

Zohaib
sumber
Anda dapat memposting pemberitahuan lokal saat aplikasi menjadi aktif dan menambahkan pengontrol tampilan Anda sebagai pengamat dan memperbarui nilai.
Adil Soomro

Jawaban:

314

Penasaran dengan urutan kejadian yang tepat, saya memasukkan aplikasi sebagai berikut: (@Zohaib, Anda dapat menggunakan kode NSNotificationCenter di bawah ini untuk menjawab pertanyaan Anda).

// 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");
}

Saat peluncuran, hasilnya terlihat seperti ini:

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

Masukkan latar belakang lalu masukkan kembali latar depan:

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
danh
sumber
1
Danh, Anda memetakan UIApplicationWillEnterForegroundNotification to appDidEnterForeground :. Bukankah itu agak menyesatkan? Perhatikan "akan" dan "lakukan". Apakah itu disengaja?
Lubiluk
@Lubiluk - tidak disengaja. Saya akan mengedit. Tangkapan yang bagus.
danh
4
Ini adalah jawaban yang sangat berguna. Saya membuat versi Swift di sini .
Suragch
Peragaan mode latar belakang yang sempurna!
Marcelo dos Santos
Apa urutan kejadian ketika Anda mengetuk dua kali tombol rumah dan menutup aplikasi?
Amjad Husseini
134

Menggunakan Objective-C

Anda harus mendaftarkan UIApplicationWillEnterForegroundNotificationdi Anda ViewController's viewDidLoadmetode dan setiap kali aplikasi kembali dari latar belakang Anda dapat melakukan apapun yang Anda ingin lakukan dalam metode terdaftar untuk pemberitahuan. ViewControllerIni viewWillAppear atau viewDidAppear tidak akan dipanggil ketika aplikasi datang kembali dari latar belakang ke latar.

-(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.
}

Jangan lupa untuk membatalkan registrasi notifikasi tempat Anda terdaftar.

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

Catatan jika Anda mendaftar viewControlleruntuk Anda UIApplicationDidBecomeActiveNotificationmaka metode Anda akan dipanggil setiap kali aplikasi Anda menjadi aktif, tidak disarankan untuk mendaftar viewControlleruntuk pemberitahuan ini.

Menggunakan Swift

Untuk menambahkan pengamat Anda dapat menggunakan kode berikut

 override func viewDidLoad() {
    super.viewDidLoad()

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

 func doYourStuff(){
     // your code
 }

Untuk menghapus pengamat Anda dapat menggunakan fungsi deinit dari swift.

deinit {
    NotificationCenter.default.removeObserver(self)
}
nsgulliver
sumber
4
Ya itu :) kadang-kadang sulit untuk menemukan jawaban :)
nsgulliver
@nsgulliver Apakah saya harus secara manual memohon membatalkan pendaftaran pemberitahuan - (void) dealloc {[[NSNotificationCenter defaultCenter] removeObserver: self]; }. Apakah aplikasi akan melakukannya untuk saya?
ios
43

Versi Swift 3.0 ++

Di Anda viewDidLoad, daftar di pusat notifikasi untuk mendengarkan ini dibuka dari tindakan latar belakang

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

Kemudian tambahkan fungsi ini dan lakukan tindakan yang diperlukan

func doSomething(){
    //...
}

Terakhir, tambahkan fungsi ini untuk membersihkan pengamat pemberitahuan saat pengontrol tampilan Anda dihancurkan.

deinit {
    NotificationCenter.default.removeObserver(self)
}
Fangming
sumber
Solusi mudah dan lurus ke depan untuk menangani notifikasi di dalam VC +1
Mo Zaatar
Tidak percaya jawaban yang baik ini terlewatkan dalam banyak pertanyaan serupa / duplikat SO lainnya.
Hugo Allexis Cardona
11

Cepat 4.2. Versi: kapan

Daftar dengan NotificationCenter viewDidLoaduntuk diberi tahu ketika aplikasi kembali dari latar belakang

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

Menerapkan metode yang harus dipanggil.

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

Anda dapat menghapus pengamat setelah ViewControllerdihancurkan. Ini hanya diperlukan di bawah iOS9 dan macOS 10.11

deinit {
    NotificationCenter.default.removeObserver(self)
}
gebirgsbärbel
sumber
1
FYI Saya cukup yakin Anda tidak perlu repot-repot menghapus pengamat lagi hari ini ...
Fattie
3

Mintalah pengontrol tampilan Anda mendaftar untuk UIApplicationWillEnterForegroundNotificationpemberitahuan dan bereaksi sesuai itu.

andreagiavatto
sumber
Bagaimana saya melakukannya? saya telah memanggil viewController saya di applicationDidBecomeActive tetapi. itu tumpang tindih viewController atau baik untuk melakukan itu?
Zohaib
2
Jangan panggil viewController Anda di applicationDidBecomeActive (yang ternyata salah karena dipanggil berkali-kali). Daftarkan untuk pemberitahuan di viewDidLoad@nsgulliver seperti yang disarankan. Anda viewDidAppearjuga akan menelepon doYourStuffuntuk mengatur label Anda dengan nilai yang diinginkan.
andreagiavatto
3

Saya pikir mendaftar untuk UIApplicationWillEnterForegroundNotification berisiko karena Anda mungkin berakhir dengan lebih dari satu pengontrol bereaksi terhadap pemberitahuan itu. Tidak ada jaminan bahwa pengontrol ini masih terlihat saat pemberitahuan diterima.

Inilah yang saya lakukan: Saya memaksa panggilan viewDidAppear pada pengontrol aktif langsung dari delegasi App metode didBecomeActive:

Tambahkan kode di bawah ini ke - (void)applicationDidBecomeActive:(UIApplication *)application

UIViewController *activeController = window.rootViewController;
if ([activeController isKindOfClass:[UINavigationController class]]) {
    activeController = [(UINavigationController*)window.rootViewController topViewController];
}
[activeController viewDidAppear:NO];
Erwan
sumber
7
Ini dijamin jika controller unregisters (sebagaimana mestinya) untuk UIApplicationWillEnterForegroundNotification dalam viewWillDisappear bukan di dealloc. Memanggil viewDidAppear secara eksplisit terlihat seperti peretasan bagi saya, itu memecah semantik (tampilan pribadi) dan dapat membingungkan orang (dari pengalaman).
joakim
3

coba tambahkan ini di applicationDelegate applicationWillEnterForeground.

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

Sesuai dokumentasi Apple:

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

Deskripsi:
Memberitahu pengendali anak penampilannya akan berubah. Jika Anda menerapkan pengontrol wadah kustom, gunakan metode ini untuk memberi tahu anak bahwa pandangannya akan muncul atau menghilang . Jangan memanggil viewWillAppear:, viewWillDisappear:, viewDidAppear:, atau viewDidDisappear:langsung .

(void)endAppearanceTransition;

Deskripsi:

Memberitahu pengendali anak penampilannya telah berubah. Jika Anda menerapkan pengontrol wadah kustom, gunakan metode ini untuk memberi tahu anak bahwa transisi tampilan selesai.

Kode sampel:

(void)applicationDidEnterBackground:(UIApplication *)application
{

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

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

}

Pertanyaan: Bagaimana saya memperbaikinya?

Jawab : Saya menemukan potongan baris ini dalam aplikasi. Baris ini membuat aplikasi saya tidak menerima pemberitahuan ViewWillAppear. Ketika saya berkomentar kalimat-kalimat ini bekerja dengan baik .

Lakshmi
sumber