Swift: ตัวเริ่มต้น ViewController ที่กำหนดเอง


87

คุณจะเพิ่มตัวเริ่มต้นที่กำหนดเองให้กับUIViewControllerคลาสย่อยใน Swift ได้อย่างไร?

ฉันได้สร้างคลาสย่อยUIViewControllerที่มีลักษณะดังนี้:

class MyViewController : UIViewController
{
    init(leftVC:UIViewController, rightVC:UIViewController, gap:Int)
    {
        self.leftVC = leftVC;
        self.rightVC = rightVC;
        self.gap = gap;

        super.init();

        setupScrollView();
        setupViewControllers();
    }
}

เมื่อฉันเรียกใช้ฉันได้รับข้อผิดพลาดร้ายแรง:

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

ฉันเคยอ่านมาแล้วว่าเมื่อเพิ่มตัวเริ่มต้นที่กำหนดเองจะต้องแทนที่ด้วยinit(coder aDecoder:NSCoder)ดังนั้นเรามาแทนที่สิ่งนั้นinitและดูว่าเกิดอะไรขึ้น:

override init(coder aDecoder: NSCoder)
{
    super.init(coder: aDecoder);
}

ถ้าฉันจะเพิ่มนี้ Xcode self.leftVC is not initialized at super.init callบ่นว่า ดังนั้นฉันเดาว่านั่นคงไม่ใช่ทางออกเช่นกัน ดังนั้นฉันจึงสงสัยว่าฉันจะเพิ่มตัวเริ่มต้นที่กำหนดเองให้กับViewControllerคลาสย่อยใน Swift ได้อย่างไร (เนื่องจากใน Objective-C ดูเหมือนจะไม่มีปัญหา)


คุณกำลังพยายามสร้างอินสแตนซ์ของคุณMyViewControllerอย่างไร?
Mike Pollard

ทำไมไม่สร้างอินสแตนซ์ทุกอย่างใน viewDidLoad () ที่นั่นคุณสามารถเริ่มต้นได้ในแบบที่คุณต้องการ
tudoricc

@MikePollard พร้อม dualViewCtrl = DualViewCtrl (leftVC: l, rightVC: r, gap: 50) ... ฉันรู้แล้วว่าฉันต้องใช้ตัวเริ่มต้น initWithNib
BadmintonCat

3
@tudoricc เนื่องจากบ่อยครั้งที่คุณต้องการคุณสมบัติของอินสแตนซ์ที่เริ่มต้นอย่างปลอดภัยในตัวเริ่มต้นด้วยพารามิเตอร์ที่กำหนด คุณไม่สามารถทำได้ใน viewDidLoad ตั้งแต่นั้นมาก็จะไม่รับประกันว่าคุณสมบัติจะพร้อมใช้งานเมื่อจำเป็น
BadmintonCat

ฉันขอโทษที่ในใจฉันเห็น viewDidLoad () เป็นตัวเริ่มต้น ขอบคุณสำหรับคำอธิบาย
tudoricc

คำตอบ:


125

แก้ได้! เราต้องเรียก initializer ที่กำหนดซึ่งในกรณีนี้คือ init ด้วย nibName เห็นได้ชัดว่า ...

init(leftVC:UIViewController, rightVC:UIViewController, gap:Int)
{
    self.leftVC = leftVC
    self.rightVC = rightVC
    self.gap = gap

    super.init(nibName: nil, bundle: nil)

    setupScrollView()
    setupViewControllers()
}

32
กำจัดกึ่งโคลอนที่น่าเกลียดเหล่านั้น :)
MobileMon

8
ฉันชอบอัฒภาค ทำให้โค้ดมีความคลุมเครือน้อยลงโดยเฉพาะอย่างยิ่งกับชื่อและลายเซ็นของ Cocoa / Cocoa-Touch API การตัดสินใจที่ไม่ดีของนักออกแบบ Swift ที่จะลบ IMHO ออก
BadmintonCat

25
IMHO ถ้าคุณพิมพ์อักขระและไม่มีผลกับไบนารีที่คอมไพล์คุณไม่ควรพิมพ์ :)
Sam Soffes

33
@SamSoffes คุณไม่ได้ใช้ช่องว่าง (พิเศษ) เลยเหรอ? และคุณทำให้สัญลักษณ์ทั้งหมดเป็นอักขระเดี่ยวหรือไม่?
Victor Jalencas

8
การสนทนานี้ทำให้ฉันนึกถึงแท็บและช่องว่างใน Silicon Valley
Aaron

14

สำหรับ UIViewController ทั่วไปคุณสามารถใช้สิ่งนี้ได้ตั้งแต่ Swift 2.0

init() {
    super.init(nibName: nil, bundle: nil)
}

11

ไม่แน่ใจว่าคุณสามารถแก้ปัญหานี้ได้ทั้งหมดหรือไม่ ... แต่ขึ้นอยู่กับว่าคุณต้องการให้อินเทอร์เฟซของชั้นเรียนมีลักษณะอย่างไรและคุณต้องการฟังก์ชัน coder หรือไม่คุณสามารถใช้สิ่งต่อไปนี้:

convenience required init(coder aDecoder: NSCoder)
{
    //set some defaults for leftVC, rightVC, and gap
    self.init(leftVC, rightVC, gap)
}

เนื่องจากinit:leftVC:rightVC:gapเป็นโปรแกรมเริ่มต้นที่กำหนดคุณจึงสามารถปฏิบัติตามข้อกำหนดในการนำไปใช้งานได้init:coderโดยทำให้เป็นเครื่องมือเริ่มต้นที่สะดวกซึ่งเรียกตัวเริ่มต้นที่คุณกำหนด

ซึ่งอาจจะดีกว่า

override init(coder aDecoder: NSCoder)
{
    super.init(coder: aDecoder);
}

เพราะถ้าคุณต้องการเริ่มต้นคุณสมบัติบางอย่างคุณจะต้องเขียนใหม่


8

สวิฟต์ 5

หากคุณต้องการเขียน initializer ที่กำหนดเองUIViewControllerซึ่งเริ่มต้นด้วยstoryBoard.instantiateViewController(withIdentifier: "ViewControllerIdentifier")

คุณสามารถเขียน initializer แบบกำหนดเองสำหรับOptionalคุณสมบัติเท่านั้น

class MyFooClass: UIViewController {
    var foo: Foo?

    init(with foo: Foo) {
        self.foo = foo
        super.init(nibName: nil, bundle: nil)
    }

    public required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.foo = nil
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.