Tampilan iPhoneWillAppear tidak menembak

116

Saya sudah membaca banyak posting tentang orang mengalami masalah dengan viewWillAppearketika Anda tidak membuat tampilan hirarki Anda hanya tepat. Masalah saya adalah saya tidak tahu apa artinya itu.

Jika saya membuat RootViewControllerdan memanggil addSubViewpengontrol itu, saya berharap tampilan yang ditambahkan akan dihubungkan untuk viewWillAppearacara.

Adakah yang punya contoh hierarki tampilan terprogram kompleks yang berhasil menerima viewWillAppearperistiwa di setiap tingkat?

Status Dokumen Apple:

Peringatan: Jika tampilan milik pengontrol tampilan ditambahkan ke hierarki tampilan secara langsung, pengontrol tampilan tidak akan menerima pesan ini. Jika Anda menyisipkan atau menambahkan tampilan ke hierarki tampilan, dan memiliki pengontrol tampilan, Anda harus mengirim pengontrol tampilan terkait pesan ini secara langsung. Gagal mengirim pengontrol tampilan, pesan ini akan mencegah animasi terkait ditampilkan.

Masalahnya adalah mereka tidak menjelaskan bagaimana melakukan ini. Apa artinya "langsung"? Bagaimana Anda "secara tidak langsung" menambahkan tampilan?

Saya cukup baru mengenal Cocoa dan iPhone jadi alangkah baiknya jika ada contoh berguna dari Apple selain omong kosong Hello World dasar.

chzk
sumber
Saya mengalami masalah ini sampai saya menyadari bahwa saya salah memahami maksud penggunaan subclass UIViewController secara umum. Lihat Pertanyaan ini. stackoverflow.com/questions/5691226/…
averydev
7
Harap berhati-hati !!! Tidak lagi benar di iOS 5 !!! Panggilan viewWillAppear dan viewDidAppear secara otomatis
Vilém Kurz

Jawaban:

55

Jika Anda menggunakan pengontrol navigasi dan menyetel delegasinya, maka metode tampilan {Will, Did} {Appear, Disappear} tidak akan dipanggil.

Anda perlu menggunakan metode delegasi pengontrol navigasi sebagai gantinya:

navigationController:willShowViewController:animated:
navigationController:didShowViewController:animated:
mmalc
sumber
2
Saya belum menetapkan delegasi pengontrol navigasi saya dan tetap saja metode tersebut tidak dipanggil. Bagaimanapun, saya mengaturnya dan kemudian saya menggunakan metode yang Anda sebutkan di atas. Terima kasih.
Dimitris
Saya melihat hal yang sama dengan Dimitris
jkp
7
Saya baru saja menguji ini di iOS4 dan iOS5: Ini TIDAK benar: Menetapkan delegasi navigationController dan kemudian mendorong tampilan ke sana AKAN mengaktifkan viewWillAppear: dll.
DaGaMs
Swift 3: func navigationController (_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {} AND func navigationController (_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {}
Naloiko Eugene
28

Saya mengalami masalah yang sama ini. Cukup kirim viewWillAppearpesan ke pengontrol tampilan Anda sebelum Anda menambahkannya sebagai subview. (Ada satu parameter BOOL yang memberi tahu pengontrol tampilan apakah sedang dianimasikan untuk muncul atau tidak.)

[myViewController viewWillAppear:NO];

Lihat RootViewController.m dalam contoh Metronom.

(Saya benar-benar menemukan proyek contoh Apple bagus. Ada BANYAK lebih dari HelloWorld;)

lajos
sumber
3
Sebenarnya, Anda harus memanggil viewWillAppear setelah Anda menambahkannya ke subview. Jika tidak, IBOutlets / IBActions tidak akan terhubung.
4thSpace
2
Ya, setelah itu. Membuat subview dari XIB, viewWillAppear tidak dipanggil. Sebut saja sendiri dan semuanya bekerja dengan baik.
JOM
Terima kasih! Ini persis untuk saya. Saya menambahkan subview secara manual melalui [scrollView addSubview:controller.view];. Saya menambahkan baris [controller viewWillAppear:NO];setelah itu dan voila! Bekerja seperti pesona.
Rob S.
Kemungkinan besar, ini karena UIViewController Anda mengontrol tampilan yang merupakan subview dari tampilan yang dikontrol oleh UIViewController lain. Ini bukan pola desain yang dimaksudkan. Untuk penjelasan lebih lanjut, lihat posting ini. stackoverflow.com/questions/5691226/…
averydev
6
Harap berhati-hati !!! Tidak lagi benar di iOS 5 !!! Memanggil viewWillAppear dan viewDidAppear secara otomatis. Jika Anda memanggilnya secara manual, itu akan dipanggil dua kali.
Vilém Kurz
18

Saya akhirnya menemukan solusi untuk ini YANG BERFUNGSI!

UINavigationControllerDelegate

Saya pikir intinya adalah mengatur delegasi kontrol navigasi Anda ke viewcontroller yang ada, dan mengimplementasikannya UINavigationControllerDelegate dan itu dua metode. Cemerlang! Saya sangat senang akhirnya saya menemukan solusi!

Chris
sumber
bagaimana cara menetapkan rootviewcontroller sebagai delegasi untuk navigationcontroller?
Gargo
1
Ini TIDAK BEKERJA! coba minimalkan aplikasi dan maksimalkan
Vyachaslav Gerchicov
8

Saya baru saja mengalami masalah yang sama. Dalam aplikasi saya, saya memiliki 2 pengontrol navigasi dan mendorong pengontrol tampilan yang sama di masing-masing berfungsi dalam satu kasus dan bukan di kasus lain. Maksud saya ketika mendorong pengontrol tampilan yang sama persis di yang pertama UINavigationController, viewWillAppeardipanggil tetapi tidak ketika didorong di pengontrol navigasi kedua.

Kemudian saya menemukan posting ini UINavigationController harus memanggil metode viewWillAppear / viewWillDisappear

Dan menyadari bahwa pengontrol navigasi kedua saya telah mendefinisikan ulang viewWillAppear. Menyaring kode menunjukkan bahwa saya tidak menelepon

[super viewWillAppear:animated];

Saya menambahkannya dan berhasil!

Dokumentasinya mengatakan:

Jika Anda mengganti metode ini, Anda harus memanggil super di beberapa titik dalam implementasi Anda.

Antoine
sumber
Hal yang sama disini. Berantakan dengan tidak menelepon super.
olivaresF
5

Saya telah menggunakan pengontrol navigasi. Ketika saya ingin turun ke tingkat data lain atau menampilkan tampilan kustom saya, saya menggunakan yang berikut ini:

[self.navigationController pushViewController:<view> animated:<BOOL>];

Ketika saya melakukan ini, saya mendapatkan viewWillAppearfungsi untuk diaktifkan. Saya kira ini memenuhi syarat sebagai "tidak langsung" karena saya sendiri tidak menyebut addSubViewmetode yang sebenarnya . Saya tidak tahu apakah ini 100% berlaku untuk aplikasi Anda karena saya tidak tahu apakah Anda menggunakan pengontrol navigasi, tetapi mungkin itu akan memberikan petunjuk.

Josh Gagnon
sumber
5

Terima kasih iOS 13.

ViewWillDisappear, ViewDidDisappear, ViewWillAppearDan ViewDidAppeartidak akan dipanggil pada menyajikan tampilan controller pada iOS 13 yang menggunakan presentasi modal baru yang tidak menutupi seluruh layar.

Penghargaan akan diberikan kepada Arek Holko . Dia benar-benar menyelamatkan hariku.

masukkan deskripsi gambar di sini

BilalReffas
sumber
4

Pertama, bilah tab harus berada di tingkat akar, yaitu ditambahkan ke jendela, seperti yang dinyatakan dalam dokumentasi Apple. Ini adalah kunci untuk perilaku yang benar.

Kedua, Anda dapat menggunakan UITabBarDelegate/ UINavigationBarDelegateuntuk meneruskan pemberitahuan secara manual, tetapi saya menemukan bahwa agar seluruh hierarki panggilan tampilan berfungsi dengan benar, yang harus saya lakukan hanyalah memanggil secara manual.

[tabBarController viewWillAppear:NO];
[tabBarController viewDidAppear:NO];

dan

[navBarController viewWillAppear:NO];
[navBarController viewDidAppear:NO];

.. hanya SEKALI sebelum mengatur pengontrol tampilan pada pengontrol masing-masing (tepat setelah alokasi). Sejak saat itu, ia dengan benar memanggil metode ini pada pengontrol tampilan anaknya.

Hirarki saya seperti ini:

window
    UITabBarController (subclass of)
        UIViewController (subclass of) // <-- manually calls [navController viewWill/DidAppear
            UINavigationController (subclass of)
                UIViewController (subclass of) // <-- still receives viewWill/Did..etc all the way down from a tab switch at the top of the chain without needing to use ANY delegate methods

Hanya memanggil metode yang disebutkan pada pengontrol tab / nav untuk pertama kalinya memastikan bahwa SEMUA kejadian diteruskan dengan benar. Itu membuat saya tidak perlu memanggil mereka secara manual dari UINavigationBarDelegate/UITabBarControllerDelegate metode.

Catatan samping: Anehnya, jika tidak berhasil, metode privat

- (void)transitionFromViewController:(UIViewController*)aFromViewController toViewController:(UIViewController*)aToViewController 

.. yang dapat Anda lihat dari callstack pada implementasi yang berfungsi, biasanya memanggil viewWill/Did.. metode tetapi tidak sampai saya melakukan hal di atas (meskipun dipanggil).

Saya pikir itu SANGAT penting bahwa UITabBarControllerada di tingkat jendela dan dokumen tampaknya mendukung ini.

Harapan yang jelas (ish), senang menjawab pertanyaan selanjutnya.

Sam
sumber
3

Karena tidak ada jawaban yang diterima dan orang-orang (seperti saya) mendarat di sini, saya memberikan variasi saya. Meskipun saya tidak yakin itu masalah aslinya. Ketika pengontrol navigasi ditambahkan sebagai subview ke tampilan lain, Anda harus memanggil sendiri metode viewWillAppear / Dissappear dll seperti ini:

- (void) viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [subNavCntlr viewWillAppear:animated];
}

- (void) viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [subNavCntlr viewWillDisappear:animated];
}

Hanya untuk melengkapi contoh. Kode ini muncul di ViewController saya tempat saya membuat dan menambahkan pengontrol navigasi ke dalam tampilan yang saya tempatkan pada tampilan.

- (void)viewDidLoad {

    // This is the root View Controller
    rootTable *rootTableController = [[rootTable alloc]
                 initWithStyle:UITableViewStyleGrouped];

    subNavCntlr = [[UINavigationController alloc]   
                  initWithRootViewController:rootTableController];

    [rootTableController release];

    subNavCntlr.view.frame = subNavContainer.bounds;

    [subNavContainer addSubview:subNavCntlr.view];

    [super viewDidLoad];
}

.h terlihat seperti ini

@interface navTestViewController : UIViewController <UINavigationControllerDelegate> {
    IBOutlet UIView *subNavContainer;
    UINavigationController *subNavCntlr;
}

@end

Dalam file pena saya memiliki tampilan dan di bawah tampilan ini saya memiliki label gambar dan wadah (tampilan lain) di mana saya meletakkan pengontrol masuk Berikut ini tampilannya. Saya harus mengacak-acak beberapa hal karena ini adalah pekerjaan untuk klien.

alt teks

hol
sumber
3

Tampilan ditambahkan "secara langsung" dengan menelepon [view addSubview:subview] . Tampilan ditambahkan "secara tidak langsung" dengan metode seperti bilah tab atau bilah navigasi yang menukar sub-tampilan.

Setiap kali Anda menelepon [view addSubview:subviewController.view], Anda harus menelepon [subviewController viewWillAppear:NO](atau YA sesuai kasus Anda).

Saya mengalami masalah ini ketika saya menerapkan sistem manajemen tampilan root kustom saya sendiri untuk sub-layar dalam sebuah game. Menambahkan panggilan secara manual ke viewWillAppear menyembuhkan masalah saya.

AndrewS
sumber
3

Cara yang benar untuk melakukannya adalah menggunakan api penahanan UIViewController.

- (void)viewDidLoad {
     [super viewDidLoad];
     // Do any additional setup after loading the view.
     UIViewController *viewController = ...;
     [self addChildViewController:viewController];
     [self.view addSubview:viewController.view];
     [viewController didMoveToParentViewController:self];
}
Hari Kunwar
sumber
Ini benar-benar solusi modern yang tepat (iOS 9,8,7). Selain itu, jika Anda mengubah pengontrol tampilan tertanam dengan cepat, Anda perlu memanggil [viewController willMoveToParentViewController: nil]; [viewController.view removeFromSuperview]; [viewController removeFromParentViewController];
Eli Burke
1
Dalam hal ini viewWillAppear:mungkin masih tidak bisa disebut
Vyachaslav Gerchicov
2

Saya menggunakan kode ini untuk pengontrol tampilan push dan pop:

Dorong:

[self.navigationController pushViewController:detaiViewController animated:YES];
[detailNewsViewController viewWillAppear:YES];

pop:

[[self.navigationController popViewControllerAnimated:YES] viewWillAppear:YES];

.. dan itu bekerja dengan baik untukku.

Arash Zeinoddini
sumber
2

Kesalahan yang sangat umum adalah sebagai berikut. Anda memiliki satu pandangan UIView* a,, dan satu lagi UIView* b,. Anda menambahkan b ke a sebagai subview. Jika Anda mencoba memanggil viewWillAppear di b, ini tidak akan pernah diaktifkan, karena ini adalah subview dari a

giuseppe
sumber
2

iOS 13 menggigit aplikasi saya di sini. Jika Anda memperhatikan perubahan perilaku pada iOS 13, atur saja yang berikut ini sebelum Anda mendorongnya:

yourVC.modalPresentationStyle = UIModalPresentationFullScreen;

Anda mungkin juga perlu menyetelnya di .storyboard di inspektur Atribut (setel Presentasi ke Layar Penuh).

Ini akan membuat aplikasi Anda berperilaku seperti pada versi iOS sebelumnya.

dollardime
sumber
1

Saya tidak 100% yakin akan hal ini, tetapi menurut saya menambahkan tampilan ke hierarki tampilan secara langsung berarti memanggil -addSubview: tampilan pengontrol tampilan (misalnya, [viewController.view addSubview:anotherViewController.view]) daripada mendorong pengontrol tampilan baru ke tumpukan pengontrol navigasi.

Martin Gordon
sumber
1

Menurut saya, menambahkan subview tidak selalu berarti tampilan akan muncul, jadi tidak ada panggilan otomatis ke metode kelas yang akan ditampilkan.


sumber
1

Saya pikir apa yang mereka maksud "secara langsung" adalah dengan menghubungkan semuanya dengan cara yang sama seperti template "Aplikasi Navigasi" xcode, yang menetapkan UINavigationController sebagai satu-satunya subview dari UIWindow aplikasi.

Menggunakan template itu adalah satu-satunya cara saya bisa mendapatkan metode Will / Did / Appear / Disappear yang dipanggil pada objek ViewControllers setelah push / pops dari pengontrol tersebut di UINavigationController. Tidak ada solusi lain dalam jawaban di sini yang berfungsi untuk saya, termasuk menerapkannya di RootController dan meneruskannya ke NavigationController (anak). Fungsi-fungsi tersebut (akan / did / muncul / menghilang) hanya dipanggil di RootController saya setelah menampilkan / menyembunyikan VC level atas, "login" dan VC navigasi saya, bukan sub-VC di pengontrol navigasi, jadi saya tidak memiliki kesempatan untuk "melewati mereka" ke Nav VC.

Saya akhirnya menggunakan fungsi delegasi UINavigationController untuk mencari transisi tertentu yang memerlukan fungsionalitas tindak lanjut di aplikasi saya, dan berfungsi, tetapi memerlukan sedikit lebih banyak pekerjaan untuk mendapatkan fungsionalitas menghilang dan muncul "disimulasikan".

Juga masalah prinsip untuk membuatnya bekerja setelah membenturkan kepala saya terhadap masalah ini selama berjam-jam hari ini. Setiap cuplikan kode yang berfungsi menggunakan RootController khusus dan VC navigasi anak akan sangat dihargai.

Bogatyr
sumber
1

Dalam hal ini membantu siapa pun. Saya memiliki masalah serupa di mana saya ViewWillAppeartidak menembaki a UITableViewController. Setelah banyak bermain-main, saya menyadari bahwa masalahnya adalah bahwa UINavigationControlleryang mengontrol saya UITableViewtidak pada tampilan root. Setelah saya memperbaikinya, sekarang berfungsi seperti juara.

Andrew
sumber
Bisakah Anda berbagi "bagaimana" Anda melakukannya?
Brabbeldas
1

Saya baru saja mengalami masalah ini sendiri dan saya butuh waktu 3 jam penuh (2 di antaranya googling) untuk memperbaikinya.

Apa yang ternyata membantu adalah cukup dengan menghapus aplikasi dari perangkat / simulator, bersihkan lalu jalankan kembali .

Semoga membantu

Finn Gaida
sumber
1
[self.navigationController setDelegate:self];

Setel delegasi ke pengontrol tampilan root.

Gaurav
sumber
1

Untuk Swift. Pertama buat protokol untuk memanggil apa yang ingin Anda panggil di viewWillAppear

protocol MyViewWillAppearProtocol{func myViewWillAppear()}

Kedua, buat kelas

class ForceUpdateOnViewAppear: NSObject, UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool){
    if let updatedCntllr: MyViewWillAppearProtocol = viewController as? MyViewWillAppearProtocol{
        updatedCntllr.myViewWillAppear()
    }
}

}

Ketiga, buat instance ForceUpdateOnViewAppear menjadi anggota kelas yang sesuai yang memiliki akses ke Pengontrol Navigasi dan ada selama pengontrol Navigasi ada. Ini mungkin sebagai contoh pengontrol tampilan root dari pengontrol navigasi atau kelas yang membuat atau menyajikannya. Kemudian tetapkan instance ForceUpdateOnViewAppear ke properti delegasi Pengontrol Navigasi sedini mungkin.

Vadim Motorine
sumber
0

Dalam kasus saya, masalah dengan animasi transisi kustom. Saat disetel modalPresentationStyle = .custom viewWillAppeartidak dipanggil

dalam kelas animasi transisi kustom perlu metode panggilan: beginAppearanceTransitiondanendAppearanceTransition

ober
sumber
0

Dalam kasus saya, itu hanya bug aneh pada emulator ios 12.1. Hilang setelah diluncurkan di perangkat nyata.

pelukan dingin
sumber
0

Saya telah membuat kelas yang memecahkan masalah ini. Cukup setel sebagai delegasi pengontrol navigasi Anda, dan terapkan satu atau dua metode sederhana di pengontrol tampilan Anda - yang akan dipanggil saat tampilan akan ditampilkan atau telah ditampilkan melalui NavigationController

Berikut GIST yang menunjukkan kodenya

GregJaskiewicz
sumber
0

ViewWillAppear adalah metode penggantian kelas UIViewController sehingga menambahkan subView tidak akan memanggil viewWillAppear, tetapi ketika Anda mempresentasikan, push, pop, show, setFront Atau popToRootViewController dari viewController maka viewWillAppear untuk viewController yang disajikan akan dipanggil.

Abu Ul Hassan
sumber
0

Masalah saya adalah bahwa viewWillAppear tidak dipanggil saat melepas dari segue. Jawabannya adalah dengan membuat panggilan ke viewWillAppear (true) dalam segmen santai di View Controller yang Anda segue kembali ke

@IBAction func unwind (untuk unwindSegue: UIStoryboardSegue, ViewController nextVC: Any) {

   viewWillAppear(true)
}
pengguna2385491
sumber
-2

Saya tidak yakin ini adalah masalah yang sama yang saya selesaikan.
Dalam beberapa kesempatan, metode tidak dijalankan dengan cara biasa seperti "[self methodOne]".

Mencoba

- (void)viewWillAppear:(BOOL)animated
{
    [self performSelector:@selector(methodOne) 
           withObject:nil afterDelay:0];
}
Sean
sumber
masalahnya viewWillAppeartidak disebut sama sekali
Vyachaslav Gerchicov
-3

Anda hanya boleh memiliki 1 UIViewController yang aktif setiap saat. Setiap subview yang ingin Anda manipulasi harus persis seperti itu - subVIEWS - yaitu UIView.

Saya menggunakan teknik sederhana untuk mengelola hierarki tampilan saya dan belum mengalami masalah sejak saya mulai melakukan berbagai hal dengan cara ini. Ada 2 poin utama:

  • satu UIViewController harus digunakan untuk mengelola "nilai layar" aplikasi Anda
  • gunakan UINavigationController untuk mengubah tampilan

Apa yang saya maksud dengan "nilai layar"? Memang sengaja dibuat agak kabur, tetapi umumnya ini adalah fitur atau bagian dari aplikasi Anda. Jika Anda memiliki beberapa layar dengan gambar latar yang sama tetapi overlay / popup berbeda, dll., Itu harus berupa 1 pengontrol tampilan dan beberapa tampilan anak. Anda seharusnya tidak pernah bekerja dengan 2 pengontrol tampilan. Perhatikan bahwa Anda masih dapat membuat instance UIView dalam satu pengontrol tampilan dan menambahkannya sebagai subview dari pengontrol tampilan lain jika Anda ingin area layar tertentu ditampilkan di beberapa pengontrol tampilan.

Adapun UINavigationController - ini adalah teman terbaik Anda! Matikan bilah navigasi dan tentukan TIDAK untuk animasi, dan Anda memiliki cara terbaik untuk beralih layar sesuai permintaan. Anda dapat mendorong dan memunculkan pengontrol tampilan jika berada dalam hierarki, atau Anda dapat menyiapkan larik pengontrol tampilan (termasuk larik yang berisi satu VC) dan menyetelnya menjadi tumpukan tampilan menggunakan setViewControllers. Ini memberi Anda kebebasan total untuk mengubah VC, sambil mendapatkan semua keuntungan bekerja dalam model yang diharapkan Apple dan membuat semua acara, dll. Diaktifkan dengan benar.

Inilah yang saya lakukan setiap kali saya memulai aplikasi:

  • mulai dari aplikasi berbasis jendela
  • tambahkan UINavigationController sebagai rootViewController jendela
  • tambahkan apa pun yang saya inginkan agar UIViewController pertama saya sebagai rootViewController dari pengontrol nav

(catatan mulai dari berbasis jendela hanyalah preferensi pribadi - Saya suka membuat sendiri jadi saya tahu persis bagaimana membuatnya. Ini akan bekerja dengan baik dengan templat berbasis tampilan)

Semua peristiwa terjadi dengan benar dan pada dasarnya hidup itu baik. Anda kemudian dapat menghabiskan seluruh waktu Anda untuk menulis bagian-bagian penting dari aplikasi Anda dan tidak mengotak-atik mencoba meretas hierarki tampilan secara manual.

Nigel Flack
sumber
Tidak ada yang salah dengan beberapa pengontrol tampilan aktif; UIViewController memiliki metode untuk memungkinkan pembuatan hierarki (mis. [AddChildViewController:]).
Richard
1
Ya sekarang. Pada tahun 2011 tidak. Jawabannya tepat pada saat itu, memang tidak sekarang.
Nigel Flack