สร้างอินสแตนซ์และนำเสนอ viewController ใน Swift


299

ปัญหา

ฉันเริ่มต้นการดูของใหม่SwiftบนXcode 6และฉันพยายามโครงการสาธิตบางและแบบฝึกหัด ตอนนี้ฉันติดอยู่ที่:

สร้างอินสแตนซ์แล้วนำเสนอ a viewControllerจากกระดานเรื่องราวเฉพาะ

Objective-C Solution

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"myStoryboardName" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"myVCID"];
[self presentViewController:vc animated:YES completion:nil];

ทำอย่างไรจึงจะได้สิ่งนี้ใน Swift?

คำตอบ:


647

คำตอบนี้ได้รับการแก้ไขล่าสุดสำหรับ Swift 5.2 และ iOS 13.4 SDK


มันเป็นเรื่องของไวยากรณ์ใหม่และ API ที่ได้รับการแก้ไขเล็กน้อย ฟังก์ชันการทำงานพื้นฐานของ UIKit ไม่ได้เปลี่ยนแปลง สิ่งนี้เป็นจริงสำหรับ iOS SDK เฟรมเวิร์กส่วนใหญ่

let storyboard = UIStoryboard(name: "myStoryboardName", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "myVCID")
self.present(vc, animated: true)

หากคุณกำลังมีปัญหากับinit(coder:)โปรดดูคำตอบของ EridB


3
คุณสามารถละเว้น;! ;) คุณจะอธิบายอย่างละเอียดเกี่ยวกับas UIViewController? ทำไมจึงจำเป็น
เซบาสเตียน Wramba

5
asคำหลักที่ใช้สำหรับการพิมพ์ มันเหมือนกับ(UIViewController *)anObjectในวัตถุประสงค์ c
Garoal

1
ใช่ฉันรู้ว่าฉันสามารถละเว้นพวกเขา แต่นั่นเป็นส่วนหนึ่งของ habbit ยาว : D ขณะที่instantiateViewControllerWithIdentifierผลตอบแทนAnyObject( idเทียบเท่าในสวิฟท์) และผมประกาศvcเป็นUIViewControllerผมต้อง typecast ไปAnyObject UIViewController
akashivskyy

สวัสดีเพื่อนฉันกำลังประสบปัญหาที่แตกต่างกันรหัสนี้ทำงานบนโปรแกรมจำลองไม่ได้อยู่ใน ipad2 ของฉันซึ่งมี iOS v7.1.2 หากคุณไม่ได้ช่วยฉันในการแก้ไขปัญหานี้
พระอินทร์

3
@akashivskyy แน่นอนที่สุดสำหรับคุณ แต่อาจไม่ถึงกับบ้าง
mmc

43

สำหรับผู้ที่ใช้คำตอบของ @ akashivskyเพื่อสร้างอินสแตนซ์UIViewControllerและมีข้อยกเว้น:

ข้อผิดพลาดร้ายแรง: การใช้ initializer ที่ยังไม่ได้ใช้ 'init (coder :)' สำหรับคลาส

เคล็ดลับด่วน:

นำไปใช้required init?(coder aDecoder: NSCoder)ที่ปลายทางของคุณด้วยตนเองUIViewControllerที่คุณพยายามจะยกตัวอย่าง

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

หากคุณต้องการคำอธิบายเพิ่มเติมโปรดอ้างอิงคำตอบของฉันที่นี่


หากคุณต้องการใช้ตัวเริ่มต้นที่กำหนดเองคุณสามารถเรียก super ด้วย super.init (nibName: nil, bundle: nil) และวิธีการที่จะโหลดแบบละเอียดหรือเรียกใช้ด้วยชื่อของไฟล์ NIB
user1700737

4
@ user1700737 ฉันกำลังสร้างอินสแตนซ์ viewController ที่อ้างถึงกระดานเรื่องราวซึ่งเรียกใช้งาน initWithCoder ไม่ใช่ initWithNib อ้างถึงคำถามนี้stackoverflow.com/questions/24036393/…
E-Riddie

สวัสดีเพื่อนฉันกำลังประสบปัญหาที่แตกต่างกันรหัสนี้ทำงานบนโปรแกรมจำลองไม่ได้อยู่ใน ipad2 ของฉันซึ่งมี iOS v7.1.2 หากคุณไม่ได้ช่วยฉันในการแก้ไขปัญหานี้
พระอินทร์

@ ภายในคุณต้องถามคำถามอื่นในกองให้ฉันลิงค์ฉันมีความสุขที่จะช่วยคุณ!
E-Riddie

ใน Swift 1.2 คุณต้องทำinit(coder aDecoder: NSCoder!)"จำเป็น" ดังนั้นตอนนี้คุณต้องเขียนสิ่งต่อไปนี้:required init(coder aDecoder: NSCoder!)
Eduardo Viegas

18

ลิงค์นี้มีทั้งการใช้งาน:

สวิฟท์:

let viewController:UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("ViewController") as UIViewController
self.presentViewController(viewController, animated: false, completion: nil)

วัตถุประสงค์ C

UIViewController *viewController = [[UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil] instantiateViewControllerWithIdentifier:@"ViewController"];

ลิงค์นี้มีรหัสสำหรับการเริ่มต้นการควบคุมการดูในกระดานเรื่องราวเดียวกัน

/*
 Helper to Switch the View based on StoryBoard
 @param StoryBoard ID  as String
*/
func switchToViewController(identifier: String) {
    let viewController = self.storyboard?.instantiateViewControllerWithIdentifier(identifier) as! UIViewController
    self.navigationController?.setViewControllers([viewController], animated: false)

}

15

คำตอบของ akashivsky นั้นใช้ได้ดี! แต่ในกรณีที่คุณมีปัญหากลับมาจากตัวควบคุมมุมมองที่นำเสนอทางเลือกนี้จะเป็นประโยชน์ มันใช้งานได้สำหรับฉัน!

สวิฟท์:

let storyboard = UIStoryboard(name: "MyStoryboardName", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("someViewController") as! UIViewController
// Alternative way to present the new view controller
self.navigationController?.showViewController(vc, sender: nil)

Obj-C:

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MyStoryboardName" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"someViewController"];
[self.navigationController showViewController:vc sender:nil];

12

รหัสที่ได้รับการปรับปรุง Swift 4.2 คือ

let storyboard = UIStoryboard(name: "StoryboardNameHere", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "ViewControllerNameHere")
self.present(controller, animated: true, completion: nil)

7
// "Main" is name of .storybord file "
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
// "MiniGameView" is the ID given to the ViewController in the interfacebuilder
// MiniGameViewController is the CLASS name of the ViewController.swift file acosiated to the ViewController
var setViewController = mainStoryboard.instantiateViewControllerWithIdentifier("MiniGameView") as MiniGameViewController
var rootViewController = self.window!.rootViewController
rootViewController?.presentViewController(setViewController, animated: false, completion: nil)

สิ่งนี้ใช้ได้ดีสำหรับฉันเมื่อฉันใส่ไว้ใน AppDelegate


7

หากคุณต้องการนำเสนออย่างสุภาพคุณควรมีบางสิ่งบางอย่างที่น่าตะลึง:

let vc = self.storyboard!.instantiateViewControllerWithIdentifier("YourViewControllerID")
self.showDetailViewController(vc as! YourViewControllerClassName, sender: self)

5

ฉันอยากจะแนะนำวิธีที่สะอาดกว่านี้มาก สิ่งนี้จะเป็นประโยชน์เมื่อเรามีกระดานเรื่องราวหลายกระดาน

1. สร้างโครงสร้างที่มีกระดานเรื่องราวทั้งหมดของคุณ

struct Storyboard {
      static let main = "Main"
      static let login = "login"
      static let profile = "profile" 
      static let home = "home"
    }

2. สร้างส่วนขยาย UIStoryboard เช่นนี้

extension UIStoryboard {
  @nonobjc class var main: UIStoryboard {
    return UIStoryboard(name: Storyboard.main, bundle: nil)
  }
  @nonobjc class var journey: UIStoryboard {
    return UIStoryboard(name: Storyboard.login, bundle: nil)
  }
  @nonobjc class var quiz: UIStoryboard {
    return UIStoryboard(name: Storyboard.profile, bundle: nil)
  }
  @nonobjc class var home: UIStoryboard {
    return UIStoryboard(name: Storyboard.home, bundle: nil)
  }
}

ให้ตัวระบุสตอรีบอร์ดเป็นชื่อคลาสและใช้รหัสด้านล่างเพื่อสร้างอินสแตนซ์

let loginVc = UIStoryboard.login.instantiateViewController(withIdentifier: "\(LoginViewController.self)") as! LoginViewController

Whats @nonobjc ทำเพื่ออะไร?
StackRunner

1
@StackRunner สิ่งนี้จะไม่สามารถใช้ได้กับวัตถุประสงค์ c
XcodeNOOB

3

สวิฟท์ 4:

    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let yourVC: YourVC = storyboard.instantiateViewController(withIdentifier: "YourVC") as! YourVC

2

หากคุณมี Viewcontroller ไม่ได้ใช้สตอรี่บอร์ด / Xib ใด ๆ คุณสามารถกดไปที่ VC เฉพาะด้านล่างนี้ได้:

 let vcInstance : UIViewController   = yourViewController()
 self.present(vcInstance, animated: true, completion: nil)

ฉันได้รับสิ่งนี้: "ไม่สามารถสร้างได้เพราะไม่มี initializers ที่สามารถเข้าถึงได้"
Paul Bénéteau

ร้านค้าและความสัมพันธ์อื่น ๆ ที่จัดทำโดยกระดานเรื่องราวหายไป
jose920405

2

สวิฟท์ 3 สตอรี่บอร์ด

let settingStoryboard : UIStoryboard = UIStoryboard(name: "SettingViewController", bundle: nil)
let settingVC = settingStoryboard.instantiateViewController(withIdentifier: "SettingViewController") as! SettingViewController
self.present(settingVC, animated: true, completion: {

})

1

ฉันรู้ว่ามันเป็นเธรดเก่า แต่ฉันคิดว่าโซลูชันปัจจุบัน (ใช้ตัวระบุสตริง hardcoded สำหรับตัวควบคุมมุมมองที่กำหนด) มีแนวโน้มที่จะเกิดข้อผิดพลาด

ฉันได้สร้างสคริปต์เวลาสร้าง (ซึ่งคุณสามารถเข้าถึงได้ที่นี่ ) ซึ่งจะสร้างวิธีการคอมไพเลอร์ที่ปลอดภัยสำหรับการเข้าถึงและควบคุมอินสแตนซ์มุมมองจากกระดานเรื่องราวทั้งหมดภายในโครงการที่กำหนด

ตัวอย่างเช่นตัวควบคุมมุมมองชื่อvc1ในMain.storyboardจะถูกยกตัวอย่างเช่น:

let vc: UIViewController = R.storyboard.Main.vc1^  // where the '^' character initialize the controller

1

ไม่ว่าฉันจะพยายามอะไรมันก็ไม่ได้ผลสำหรับฉัน - ไม่มีข้อผิดพลาด แต่ไม่มีคอนโทรลเลอร์มุมมองใหม่บนหน้าจอของฉัน ไม่ทราบว่าทำไม แต่การห่อในฟังก์ชันไทม์เอาต์ในที่สุดก็ทำให้มันทำงาน:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.0) {
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let controller = storyboard.instantiateViewController(withIdentifier: "TabletViewController")
    self.present(controller, animated: true, completion: nil)
}


0

ฉันสร้างห้องสมุดที่จะจัดการเรื่องนี้ง่ายขึ้นด้วยไวยากรณ์ที่ดีกว่า:

https://github.com/Jasperav/Storyboardable

เพียงแค่เปลี่ยน Storyboard.swift และปล่อยให้เป็นไปตามViewControllersStoryboardable

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