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


156

ฉันตัดสินใจดำเนินการโปรเจ็กต์ที่เหลือต่อด้วย Swift เมื่อฉันเพิ่มคลาสที่กำหนดเอง (subclass ของUIViewcontroller) ไปยังตัวควบคุมมุมมองสตอรี่บอร์ดของฉันและโหลดโปรเจ็กต์แอพก็ขัดข้องทันทีโดยมีข้อผิดพลาดดังต่อไปนี้:

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

นี่คือรหัส:

import UIKit

class TestViewController: UIViewController {

    init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        // Custom initialization
    }

    override func viewDidLoad() {
        super.viewDidLoad()
              // Do any additional setup after loading the view.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    /*
    // #pragma mark - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
        // Get the new view controller using [segue destinationViewController].
        // Pass the selected object to the new view controller.
    }
    */
}

กรุณาแนะนำบางอย่าง

คำตอบ:


207

ปัญหา

นี้เกิดจากการขาดหายไปของการเริ่มต้นที่เป้าหมายinit?(coder aDecoder: NSCoder) UIViewControllerวิธีการนั้นเป็นสิ่งจำเป็นเพราะการยกตัวอย่างUIViewControllerจากการUIStoryboardโทรมัน

หากต้องการดูวิธีการเริ่มต้นUIViewControllerจาก a UIStoryboardโปรดดูที่นี่

ทำไมจึงไม่มีปัญหากับ Objective-C

เนื่องจากObjective-CจะรับUIViewControllerค่าเริ่มต้นที่จำเป็นทั้งหมดโดยอัตโนมัติ

เหตุใด Swift จึงไม่ได้รับค่าเริ่มต้นโดยอัตโนมัติ

Swiftโดยค่าเริ่มต้นไม่ได้รับค่าเริ่มต้นเนื่องจากความปลอดภัย แต่มันจะสืบทอดค่าเริ่มต้นทั้งหมดจากซูเปอร์คลาสหากคุณสมบัติทั้งหมดมีค่า (หรือเป็นทางเลือก) และคลาสย่อยไม่ได้กำหนดค่าเริ่มต้นที่กำหนดไว้


สารละลาย

1. วิธีแรก

ดำเนินการinit?(coder aDecoder: NSCoder)ตามเป้าหมายด้วยตนเองUIViewController

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

2. วิธีที่สอง

การลบinit(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?)เป้าหมายของคุณUIViewControllerจะรับค่าเริ่มต้นที่จำเป็นทั้งหมดจากซุปเปอร์คลาสดังที่Dave Woodชี้ไปที่คำตอบของเขาด้านล่าง



4
ขอบคุณสำหรับสิ่งนี้. ติดตามอย่างรวดเร็ว ... เมื่อคุณสร้างไฟล์ TableViewController, Xcode รวมอยู่แล้วinit(style: UITableViewStyle) { super.init(style: style) // Custom initialization } ทำไมเราถึงมีสองฟังก์ชั่น init? และความคิดใดที่ว่าทำไม Apple ถึงไม่มีค่าเริ่มต้นที่ 2 โดยค่าเริ่มต้น
เทรเวอร์ McKendrick

สิ่งนี้ไม่มีส่วนเกี่ยวข้องกับ iOS 7 หรือ iOS 8 สิ่งนี้เชื่อมโยงกับวิธีการที่ Swift สืบทอดความเป็นตัวตน!
Sulthan

init สาธารณะ (ดู: UIViewController, เฟรม: CGRect) {self.viewController = ดู self.imageName = "" self.actionName = "" super.init (เฟรม: เฟรม)}
scrainie

วิธีแรกใช้ได้ผล! ในที่สุดตารางไดนามิกของฉันก็เต็มไปด้วยเซลล์ไดนามิก !!! ทั้งหมดเป็นเพราะfatalError( "init(coder:) has not been implemented")สายหยุดแอพของฉัน
Jose Manuel Abarca Rodríguez

25

ตัวเลือกอื่นนอกเหนือจาก @ 3r1d คือการลบวิธีการ init ต่อไปนี้ออกจากชั้นเรียนของคุณ:

init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    // Custom initialization
}

การรวมเมธอด init นั้นป้องกันคลาสย่อยจากการสืบทอดinit(coder aDecoder: NSCoder!)คลาสซูเปอร์ของมัน โดยไม่รวมคลาสของคุณจะสืบทอดทั้งสองอย่าง

หมายเหตุ: ดู WWDC 2014 เซสชัน 403 "Intermediate Swift" ที่ประมาณ 33:50 เพื่อดูรายละเอียดเพิ่มเติม


ขอบคุณสำหรับการชี้ให้เห็นคำอธิบายในเซสชั่น 403 แต่ถ้าคลาสเด็กมีตัวเริ่มต้นที่สะดวกเท่านั้น
jamiltz

1
ใช่. คุณป้องกันไม่ให้วิธีการเริ่มต้นคลาสซูเปอร์มาจากการสืบทอดถ้าคุณให้วิธีการเริ่มต้นที่กำหนดของคุณเอง (ผู้ที่เรียกว่า super inits) แล้วคุณจะต้องระบุในไฟล์ของซุปเปอร์ที่ให้การสนับสนุนด้วยการเพิ่มชั้นเรียนของคุณและเพียงแค่การเรียกรุ่นซุปเปอร์ (ในขณะที่คำตอบ @ 3r1d ของ)
เดฟไม้

การมีความสะดวกสบายเพียง init () โดยไม่มี (กำหนดไว้) init () ในคลาสลูกของคุณจะทำให้เกิดข้อผิดพลาดในการคอมไพล์ นั่นเป็นเพราะฟังก์ชั่น init สะดวกสบาย () จะต้องเรียกว่า self.init () ภายในนิยามฟังก์ชัน
Ohmy

@narumolPug ไม่ถูกต้อง คุณไม่จำเป็นต้องรวมinitวิธีการที่กำหนดไว้ คลาสลูกของคุณจะสืบทอดมาจากคลาสซุปเปอร์ คุณยังสามารถโทรหาได้self.init()ซึ่งจะรันเวอร์ชันซุปเปอร์
เดฟวู้ด

คุณสามารถดูช่วงเวลาที่แน่นอนของวิดีโอได้ที่นี่youtu.be/W1s9ZjDkSN0?t=2030
Honey

10

สำหรับผู้ที่มีปัญหาเดียวกันกับ swift UICollectionViewCellsให้เพิ่มรหัสที่ @ 3r1d แนะนำให้กับUICollectionViewCellคลาสที่คุณกำหนดเองและไม่ไปที่ View Controller:

init(coder aDecoder: NSCoder!)
{
    super.init(coder: aDecoder)
}

UICollectionViewCell ใดที่คุณอ้างถึง เริ่มต้นด้วย coder เป็นวิธีในการเริ่มต้น viewController
E-Riddie

ไม่ใช่ในตัวอย่างนี้ แต่ในกรณีที่ทุกคนมีปัญหากับมัน (ฉันทำ) ... ถ้าคุณพยายามใช้ UICollectionViewController ในไฟล์. swift ของเซลล์ที่กำหนดเองคุณต้องใส่ init กับ coder
Nick Yap

2
คุณต้องเพิ่มรหัสนี้ทุกครั้งที่คุณใช้อินสแตนซ์ของ instantiation stackoverflow.com/questions/24035984/ นี้
E-Riddie

3

สำหรับผู้ที่ต้องการรหัสใน Swift:

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

[แก้ไข] สิ่งนี้มีไว้สำหรับ Swift รุ่นเก่ากว่า อาจไม่ทำงานอีกต่อไป


3

ฉันมีปัญหานี้ในเซลล์คอลเลกชันแบบเป็นโปรแกรมและแม้ว่า op จะถามเกี่ยวกับ vc ฉันยังคงใช้คำถามนี้เมื่อค้นหาคำตอบ สำหรับฉันปัญหาคือฉันไม่ได้มี

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

ดำเนินการแล้วคำตอบยอดนิยมไม่ทำงาน สิ่งที่ฉันไม่ได้มีในเซลล์คือ initializer:

// my programmatic cell was missing this
override init(frame: CGRect) {
    super.init(frame: frame)
}

เมื่อฉันเพิ่มมันข้อผิดพลาดก็หายไป


1

แทนที่จะเพิ่มวิธีการบางอย่างในการทำให้กลไกภายในทำงานได้ดีฉันจะไปกำหนดคุณลักษณะของฉันเป็น @lazy และกำหนดค่าเริ่มต้นในขอบเขตของคลาส


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