Storyboard - lihat ViewController di AppDelegate

122

pertimbangkan skenario berikut: Saya memiliki aplikasi berbasis storyboard. Saya menambahkan objek ViewController ke storyboard, menambahkan file kelas untuk ViewController ini ke dalam proyek dan menentukan nama kelas baru di inspektur identitas IB. Sekarang bagaimana saya akan merujuk ke ViewController ini secara terprogram dari AppDelegate? Saya telah membuat variabel dengan kelas yang relevan dan mengubahnya menjadi properti IBOutlet, tetapi saya tidak melihat cara apa pun untuk dapat merujuk ke ViewController baru dalam kode - setiap upaya untuk ctrl-seret koneksi tidak berfungsi .

yaitu dalam AppDelegate saya bisa mendapatkan ViewController dasar seperti ini

(MyViewController*) self.window.rootViewController

tapi bagaimana dengan ViewController lain yang ada di dalam storyboard?

Matthias D
sumber
Periksa jawaban ini . Ini cepat, tetapi bahasanya mirip.
Borzh

Jawaban:

165

Lihat dokumentasi untuk -[UIStoryboard instantiateViewControllerWithIdentifier:]. Ini memungkinkan Anda untuk membuat contoh pengontrol tampilan dari storyboard Anda menggunakan pengenal yang Anda setel di IB Attributes Inspector:

masukkan deskripsi gambar di sini

DIEDIT untuk menambahkan kode contoh:

UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"MainStoryboard"
                                                         bundle: nil];

MyViewController *controller = (MyViewController*)[mainStoryboard 
                    instantiateViewControllerWithIdentifier: @"<Controller ID>"];
Robin Summerhill
sumber
Hai Robin, terima kasih untuk itu! Saya melihat dokumen ini tetapi mendapatkan kata-kata yang dipakai dan menginisialisasi bercampur ... ini membawa kita ke sana (setelah mengikuti instruksi Anda :) (sialan kurangnya pemformatan kode dalam balasan ...) UIStoryboard * mainStoryboard = [UIStoryboard storyboardWithName: @ Paket "MainStoryboard": nil]; MyViewController * thisController = (MyViewController *) [mainStoryboard instantiateViewControllerWithIdentifier: @ "myvc"];
Matthias D
Saya telah menambahkan kode contoh Anda ke jawaban dengan pemformatan untuk siapa saja yang melihat ini.
Robin Summerhill
24
jika Anda membuat aplikasi universal, pastikan untuk menggunakan MainStoryboard_iPhone / MainStoryboard_iPad jika tidak, Anda akan mengalami crash.
roocell
16
Dari dalam delegasi Anda dapat mengakses instance storyboard yang dimuat oleh info.plist Anda seperti ini: [[[self window] rootViewController] storyboard] Menurut dokumen, ini akan mengembalikan "storyboard tempat pengontrol tampilan berasal." (atau nol jika tidak berasal dari storyboard). Dari UIStoryboard * itu, Anda dapat menggunakan panggilan instantiate yang disebutkan @RobinSummerhill. Perhatikan bahwa Storyboards membuat instance baru dari viewControllers ( adegan ) Anda saat diperlukan dan tidak menggunakan kembali yang sebelumnya dilihat.
Tad Bumcrot
6
Saya yakin OP ingin tahu CARA MENDAPATKAN DI vc YANG BERJALAN SAAT INI. Bukan cara memuatnya. Persis seperti yang dia jelaskan, Anda dulu bisa mengatakan self.window.rootViewController ini dan sekarang Anda tidak bisa lagi.
Fattie
41

Jika Anda menggunakan XCode5 Anda harus melakukannya dengan cara yang berbeda.

  • Pilih Anda UIViewControllerdiUIStoryboard
  • Pergi ke Identity Inspectordi panel kanan atas
  • Centang Use Storyboard IDkotaknya
  • Tuliskan id unik ke Storyboard IDbidang tersebut

Kemudian tulis kode Anda.

// Override point for customization after application launch.

if (<your implementation>) {
    UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" 
                                                             bundle: nil];
    YourViewController *yourController = (YourViewController *)[mainStoryboard 
      instantiateViewControllerWithIdentifier:@"YourViewControllerID"];
    self.window.rootViewController = yourController;
}

return YES;
Faruk Toptas
sumber
4
Sejauh yang saya tahu dan bisa mencobanya, ini adalah jawaban yang diperbarui.
gnclmorais
Nama storyboard adalah nama file-nya tanpa ekstensi sehingga bisa juga menjadi "Main_iPhone" atau "Main_iPad" jika Anda telah menyiapkan proyek Anda seperti itu.
Brian White
lalu bagaimana kita beralih kembali ke rootViewController asli setelah login. Setidaknya sepengetahuan saya tentang iOS 7 dan Xcode 5.0.2 - mengubah kembali pengontrol tampilan root akan langsung dan tanpa animasi mengalihkan hierarki tampilan. Tim UX telah membunuh pembuat kode dengan harga yang lebih murah.
lol
Bagaimana saya melakukannya menggunakan Swift?
Leo Dabus
8

Umumnya, sistem harus menangani pembuatan instance pengontrol tampilan dengan storyboard. Yang Anda inginkan adalah melintasi hierarki viewController dengan mengambil referensi ke alih-alih self.window.rootViewControllermenginisialisasi pengontrol tampilan, yang seharusnya sudah diinisialisasi dengan benar jika Anda telah menyiapkan storyboard dengan benar.

Jadi, katakanlah Anda rootViewControlleradalah UINavigationController dan kemudian Anda ingin mengirim sesuatu ke pengontrol tampilan teratasnya, Anda akan melakukannya seperti ini di AppDelegate Anda didFinishLaunchingWithOptions:

UINavigationController *nav = (UINavigationController *) self.window.rootViewController;
MyViewController *myVC = (MyViewController *)nav.topViewController;
myVC.data = self.data;

Di Swift, jika akan sangat mirip:

let nav = self.window.rootViewController as! UINavigationController;
let myVC = nav.topViewController as! MyViewController
myVc.data = self.data

Anda sebaiknya tidak menginisialisasi pengontrol tampilan menggunakan id storyboard dari delegasi aplikasi kecuali jika Anda ingin melewati cara normal storyboard dimuat dan memuat sendiri seluruh storyboard. Jika Anda harus menginisialisasi adegan dari AppDelegate, kemungkinan besar Anda melakukan kesalahan. Maksud saya membayangkan Anda, karena alasan tertentu, ingin mengirim data ke pengontrol tampilan di bawah tumpukan, AppDelegate tidak boleh menjangkau cara ke tumpukan pengontrol tampilan untuk mengatur data. Itu bukan urusannya. Bisnisnya adalah rootViewController. Biarkan rootViewController menangani anaknya sendiri! Jadi, jika saya melewati proses pemuatan storyboard normal oleh sistem dengan menghapus referensi ke dalamnya di file info.plist, saya paling banyak akan membuat contoh rootViewController menggunakaninstantiateViewControllerWithIdentifier:, dan mungkin akarnya jika itu adalah sebuah container, seperti UINavigationController. Yang ingin Anda hindari adalah membuat instance pengontrol tampilan yang telah dibuat oleh storyboard. Ini adalah masalah yang sering saya lihat. Singkatnya, saya tidak setuju dengan jawaban yang diterima. Ini tidak benar kecuali poster bermaksud untuk menghapus pemuatan storyboard dari info.plist karena Anda akan memuat 2 storyboard jika tidak, yang mana tidak masuk akal. Ini mungkin bukan kebocoran memori karena sistem menginisialisasi adegan root dan menetapkannya ke jendela, tetapi kemudian Anda datang dan membuat instance lagi dan menetapkannya lagi. Aplikasi Anda dimulai dengan awal yang sangat buruk!

smileBot
sumber
0
    UIStoryboard * storyboard = [UIStoryboard storyboardWithName:@"Tutorial" bundle:nil];
    self.window.rootViewController = [storyboard instantiateInitialViewController];
Ofir Malachi
sumber