线程 1:致命错误:init(coder:) 尚未实现

Posted

技术标签:

【中文标题】线程 1:致命错误:init(coder:) 尚未实现【英文标题】:Thread 1: Fatal error: init(coder:) has not been implemented 【发布时间】:2022-01-23 03:19:09 【问题描述】:

我是 Xcode 和 Swift 的新手。

这是我的第一个程序。

我包含完整的代码。

我收到此错误,但不知道如何解决。

程序构建正常,但是当我运行它时出现此错误。

感谢您提供编码解决方案。

这是 ResultView Controller.swift 文件。

//
//  ResultsViewController.swift
//  PersonalityQuiz
//
//  Created by Ricardo E. Marrero Guzmán on 12/16/21.
//

import UIKit

class ResultsViewController: UIViewController 

    @IBOutlet var resultAnswerLabel: UILabel!
    @IBOutlet var resultDefinitionLabel: UILabel!
    
    var responses: [Answer]  // Esto provoca un error.  Para quitarlo se añade el siguiente init?...
    
    init?(coder: NSCoder, responses: [Answer])   // Este init?... provoca otro error.  Se le da fix y se crea el siguiente required init?...
        self.responses = responses
        super.init(coder: coder)
    
    
    required init?(coder: NSCoder) 
        fatalError("init(coder:) has not been implemented") // Thread 1: Fatal error: init(coder:) has not been implemented
    

override func viewDidLoad() 
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        
        calculatePersonalityResults()
        navigationItem.hidesBackButton = true
    
    
    func calculatePersonalityResults() 
        
        let frecuencyOfAnswers = responses.reduce(into: [:]) 
            (counts, answer) in counts[answer.type, default: 0] += 1
        
let frequentAnswersStored = frecuencyOfAnswers.sorted(by:
         (pair1, pair2) in
            return pair1.value > pair2.value
        )
        
        let mostCommonAnswer = frequentAnswersStored.first!.key
        
        resultAnswerLabel.text = "You are \(mostCommonAnswer.rawValue)!"
        resultDefinitionLabel.text = mostCommonAnswer.definition


这是 de QuestionViewController.swift 文件

//
//  QuestionViewController.swift
//  PersonalityQuiz
//
//  Created by Ricardo E. Marrero Guzmán on 12/16/21.
//

import UIKit

class QuestionViewController: UIViewController 
    
    @IBOutlet var questionLabel: UILabel!
    
    @IBOutlet var singleStackView: UIStackView!
    @IBOutlet var singleButton1: UIButton!
    @IBOutlet var singleButton2: UIButton!
    @IBOutlet var singleButton3: UIButton!
    @IBOutlet var singleButton4: UIButton!
    
    @IBOutlet var multipleStackView: UIStackView!
    @IBOutlet var multiLabel1: UILabel!
    @IBOutlet var multiLabel2: UILabel!
    @IBOutlet var multiLabel3: UILabel!
    @IBOutlet var multiLabel4: UILabel!
    
    @IBOutlet var multiSwitch1: UISwitch!
    @IBOutlet var multiSwitch2: UISwitch!
    @IBOutlet var multiSwitch3: UISwitch!
    @IBOutlet var multiSwitch4: UISwitch!
    
    @IBOutlet var rangedStackView: UIStackView!
    @IBOutlet var rangedLabel1: UILabel!
    @IBOutlet var rangedLabel2: UILabel!
    
    @IBOutlet var rangedSlider: UISlider!
    
    @IBOutlet var questionProgressView: UIProgressView!

var answersChosen: [Answer] = [] // No se donde va esto
    
    override func viewDidLoad() 
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        
        updateUI()
        
    
    
    @IBAction func singleAnswerButtonPressed(_ sender: UIButton) 
        let currentAnswers = questions[questionIndex].answers
        
        switch sender 
        case singleButton1:
            answersChosen.append(currentAnswers[0])
        case singleButton2:
            answersChosen.append(currentAnswers[1])
        case singleButton3:
            answersChosen.append(currentAnswers[2])
        case singleButton4:
            answersChosen.append(currentAnswers[3])
        default:
            break
        
        
        nextQuestion()
    
    
    @IBAction func multipleAnswerButtonPressed() 
        let currentAnswers = questions[questionIndex].answers
        
        if multiSwitch1.isOn 
            answersChosen.append(currentAnswers[0])
        
        if multiSwitch2.isOn 
            answersChosen.append(currentAnswers[1])
        
        if multiSwitch3.isOn 
            answersChosen.append(currentAnswers[2])
        
        if multiSwitch4.isOn 
            answersChosen.append(currentAnswers[3])
        
        
        nextQuestion()
    
    
    @IBAction func rangedAnswerButtonPressed() 
        let currentAnswers = questions[questionIndex].answers
        
        let index = Int(round(rangedSlider.value * Float(currentAnswers.count - 1)))
        
        answersChosen.append(currentAnswers[index])
        
        nextQuestion()
    
    
    func updateUI() 
        singleStackView.isHidden = true
        multipleStackView.isHidden = true
        rangedStackView.isHidden = true
        
        let currentQuestion = questions[questionIndex]
        let currentAnswers = currentQuestion.answers
        let totalProgress = Float(questionIndex) / Float(questions.count)
        
        navigationItem.title = "Question #\(questionIndex + 1)"
        questionLabel.text = currentQuestion.text
        questionProgressView.setProgress(totalProgress, animated: true)
        
        switch currentQuestion.type 
        case .single:
            singleStackView.isHidden = false
            updateSingleStack(using: currentAnswers)
        case .multiple:
            multipleStackView.isHidden = false
            updateMultipleStack(using: currentAnswers)
        case .ranged:
            rangedStackView.isHidden = false
            updateRangedStack(using: currentAnswers)
        
    
    
    func updateSingleStack(using answers: [Answer]) 
        singleStackView.isHidden = false
        singleButton1.setTitle(answers[0].text, for: .normal)
        singleButton2.setTitle(answers[1].text, for: .normal)
        singleButton3.setTitle(answers[2].text, for: .normal)
        singleButton4.setTitle(answers[3].text, for: .normal)
    
    
    func updateMultipleStack(using answers: [Answer]) 
        multipleStackView.isHidden = false
        
        multiSwitch1.isOn = false
        multiSwitch2.isOn = false
        multiSwitch3.isOn = false
        multiSwitch4.isOn = false
        
        multiLabel1.text = answers[0].text
        multiLabel2.text = answers[1].text
        multiLabel3.text = answers[2].text
        multiLabel4.text = answers[3].text
    
    
    func updateRangedStack(using answers: [Answer]) 
        rangedStackView.isHidden = false
        
        rangedSlider.setValue(0.5, animated: false)
        
        rangedLabel1.text = answers.first?.text
        rangedLabel2.text = answers.last?.text
    
    
    func nextQuestion()  // Este es el método más importante del programa y lo que hace correr el app bien.
        questionIndex += 1
        
        if questionIndex < questions.count 
            updateUI()
         else 
            performSegue(withIdentifier: "Results", sender: nil)
        
    

    @IBSegueAction func showResults(_ coder: NSCoder) -> ResultsViewController? 
        return ResultsViewController(coder: coder, responses: answersChosen)
    

这是 Question.swift 文件。

//
//  Question.swift
//  PersonalityQuiz
//
//  Created by Ricardo E. Marrero Guzmán on 12/17/21.
//

import Foundation

struct Question 
    var text: String
    var type: ResponseType
    var answers: [Answer]


enum ResponseType 
    case single, multiple, ranged


struct Answer 
    var text: String
    var type: AnimalType


enum AnimalType: Character 
    case dog = "????", cat = "????", rabbit = "????", turtle = "????"
    
    var definition: String 
        switch self 
        case .dog:
            return "You are incredibly outgoing.  You sorround yourself with the people you love and enjoy activities with your friends."
        case .cat:
            return "Mischievous, yet mild-tempered, you enjoy doing things on your own terms."
        case .rabbit:
            return "You love everithings that's soft.  You are healthy and full of energy."
        case .turtle:
            return "You are wise beyond your years, and you focus on the details.  Slow and steady wins the race."
        
    


var questions: [Question] = [
    Question(
        text: "Which food do you like the most?",
        type: .single,
        answers: [
            Answer(text: "Steak", type: .dog),
            Answer(text: "Fish", type: .cat),
            Answer(text: "Carrots", type: .rabbit),
            Answer(text: "Corn", type: .turtle)
        ]
    ),
    
    Question(
        text: "Which activities do you enjoy?",
        type: .multiple,
        answers: [
            Answer(text: "Swimming", type: .turtle),
            Answer(text: "Sleeping", type: .cat),
            Answer(text: "Cuddling", type: .rabbit),
            Answer(text: "Eating", type: .dog)
        ]
    ),
    
    Question(
        text: "How much do you enjoy car rides?",
        type: .ranged,
        answers: [
            Answer(text: "I dislike them", type: .cat),
            Answer(text: "I get a little nervous", type: .rabbit),
            Answer(text: "I barely notice them", type: .turtle),
            Answer(text: "I love them", type: .dog)
        ]
    )
]

var questionIndex = 0

这是介绍ViewController的文件。

//
//  ViewController.swift
//  PersonalityQuiz
//
//  Created by Ricardo E. Marrero Guzmán on 12/16/21.
//

import UIKit

class IntroductionViewController: UIViewController 

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

    @IBAction func unwindToQuizIntroduction(segue: UIStoryboardSegue) 
        
    



【问题讨论】:

如果您使用情节提要,您的自定义 init 将不会被调用,因此您可以删除它和另一个调用 fatalError 的 init。而是使用 prepare for segue 来设置您的 Answer 数组。 查看here 及其下方的评论 【参考方案1】:

看起来你错误地实例化了你的视图控制器 您没有共享足够的代码,但我可以假设您忘记从 xib 加载 Xcode 试试这个:

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

【讨论】:

【参考方案2】:

当 UIViewController 从 Storyboard 实例化时,它会调用 required init?(coder: NSCoder),目前只是抛出一个致命错误。 您可以做以下三件事之一:

    如 Joakim 所说,要么删除 required init?(coder: NSCoder)init?(coder: NSCoder, responses: [Answer]),然后使用 segue 实例化它

    或者像这样删除init?(coder: NSCoder, responses: [Answer])并正确实现required init?(coder: NSCoder)

required init?(coder: NSCoder) 
    self.responses = [Answer]()
    super.init(coder: coder)

    您也可以在声明时初始化[Answer],这样就不需要required init?(coder: NSCoder),并且可以删除两个init,就像选项1一样:
 var responses = [Answer]()

【讨论】:

【参考方案3】:

您需要在您的QuestionViewController 中实现prepare(for: segue) 并使用此函数来传递您的Answer 数组

override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
    if (segue.identifier == "Results") 
        let viewController = segue.destination as? MyOrderDetailsVC
        viewController!.responses = answersChosen
    

【讨论】:

【参考方案4】:

终于找到了解决办法。问题是丢失的 segue 连接。我重新连接 segue 而不更改程序中的任何内容,并且解决方案来了。

谢谢,感谢您提出的解决方案建议。

【讨论】:

以上是关于线程 1:致命错误:init(coder:) 尚未实现的主要内容,如果未能解决你的问题,请参考以下文章

UIViewController 和所需的初始化?(编码器:)

致命错误:尚未为模型“a”注册架构。使用 mongoose.model(name, schema)

Swift init 方法错误:声明 'init(coder:)' 不能覆盖多个超类声明

grunt test - 致命错误:尚未实施单元测试

Swift:错误:'必需'初始化程序'init(coder :)'必须由'UIView'的子类提供

Laravel 7致命错误:未捕获的RuntimeException:尚未设置外观根