質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

2回答

1280閲覧

オプショナル型の変数をアンラップした時にnilが出て、アプリが動かなくなってしまい困っています

oilfriedchicken

総合スコア18

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2018/12/07 08:01

編集2018/12/07 08:18

初心者です。よろしくお願いいたします。

前提・実現したいこと

swift3を使って本を参考に簡単なクイズアプリを作成しています。
エラーが出ないようにしたいです。

発生している問題・エラーメッセージ

スタート画面から問題表示画面に移行するときに以下のエラーが出てしまう
以下ソースコードになります。

エラーメッセージ
unexpectedly found nil while unwrapping an Optional value

以下の部分でEXC_BAD_INSTRUCTION(code=EXC_INVOP,subcode=0x0)と表示され、アプリが停止してしまいます。

swift

1questionNoLabel.text = "Q.(questionData.questionNo)"

該当のソースコード

問題画面とスタート画面とデータベースのコードを置いておきます。よろしくお願いいたします。

問題画面

swift

1import UIKit 2import AudioToolbox 3 4 5class QuestionViewController: UIViewController{ 6 7 var questionData: QuestionData! 8 9 @IBOutlet weak var questionNoLabel: UILabel! 10 @IBOutlet weak var questionTextView: UITextView! 11 @IBOutlet weak var answer1Button: UIButton! 12 @IBOutlet weak var answer2Button: UIButton! 13 @IBOutlet weak var answer3Button: UIButton! 14 @IBOutlet weak var answer4Button: UIButton! 15 @IBOutlet weak var correctImageView: UIImageView! 16 @IBOutlet weak var incorrectImageView: UIImageView! 17 18 override func viewDidLoad() { 19 super.viewDidLoad() 20 21 questionNoLabel.text = "Q.(questionData.questionNo)" 22 questionTextView.text = questionData.question 23 answer1Button.setTitle(questionData.answer1,for: UIControlState.normal) 24 answer2Button.setTitle(questionData.answer2,for: UIControlState.normal) 25 answer3Button.setTitle(questionData.answer3,for: UIControlState.normal) 26 answer4Button.setTitle(questionData.answer4,for: UIControlState.normal) 27 } 28 29 override func didReceiveMemoryWarning() { 30 super.didReceiveMemoryWarning() 31 } 32 @IBAction func tapAnswer1Button(_ sender: Any) { 33 questionData.userChoiceAnswerNumber = 1 34 goNextQuestionWithAnimation() 35 } 36 @IBAction func tapAnswer2Button(_ sender: Any){ 37 questionData.userChoiceAnswerNumber = 2 38 goNextQuestionWithAnimation() 39 } 40 41 @IBAction func tapAnswer3Button(_ sender: Any) { 42 questionData.userChoiceAnswerNumber = 3 43 goNextQuestionWithAnimation() 44 } 45 46 @IBAction func tapAnswer4Button(_ sender: Any) { 47 questionData.userChoiceAnswerNumber = 4 48 goNextQuestionWithAnimation() 49 50 } 51 func goNextQuestionWithAnimation(){ 52 if questionData.isCorrect(){ 53 goNextQuestionWithCorrectAnimation() 54 } else{ 55 goNextQuestionWithInCorrectAnimation() 56 } 57 } 58 func goNextQuestionWithCorrectAnimation(){ 59 AudioServicesPlayAlertSound(1025) 60 UIView.animate(withDuration: 2.0, animations:{ 61 self.correctImageView.alpha = 1.0 62 }){(Bool) in self.goNextQuestion() 63 } 64 } 65 func goNextQuestionWithInCorrectAnimation(){ 66 AudioServicesPlayAlertSound(1006) 67 UIView.animate(withDuration: 2.0, animations:{ 68 self.correctImageView.alpha = 1.0 69 }){(Bool) in self.goNextQuestion() 70 } 71 } 72 func goNextQuestion(){ 73 guard let nextQuestion = QuestionDataManager.sharedInstance.nextQuestion() else{ 74 if let resultViewController = storyboard?.instantiateViewController(withIdentifier: "result") as? ResultViewController{ 75 present(resultViewController, animated: true, completion: nil) 76 } 77 return 78 } 79 if let nextQuestionViewController = storyboard?.instantiateViewController(withIdentifier: "question") 80 as? QuestionViewController{ 81 82 nextQuestionViewController.questionData = nextQuestion 83 present(nextQuestionViewController, animated: true,completion: nil) 84 } 85 } 86} 87 88

スタート画面

import UIKit class StartViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() } override func didReceiveMemoryWarning(){ super.didReceiveMemoryWarning() } override func prepare(for segue: UIStoryboardSegue, sender:Any?){ QuestionDataManager.sharedInstance.loadQuestion() guard let nextViewController = segue.destination as? QuestionViewController else { return } guard let questionData = QuestionDataManager.sharedInstance.nextQuestion() else { return } nextViewController.questionData = questionData } @IBAction func goToTitle(_ segue: UIStoryboardSegue){ } }

データベース

import Foundation class QuestionData { var question: String var answer1: String var answer2: String var answer3: String var answer4: String var correctAnswerNumber: Int var userChoiceAnswerNumber: Int? var questionNo: Int = 0 init(questionSourceDataArray: [String]){ question = questionSourceDataArray[0] answer1 = questionSourceDataArray[1] answer2 = questionSourceDataArray[2] answer3 = questionSourceDataArray[3] answer4 = questionSourceDataArray[4] correctAnswerNumber = Int(questionSourceDataArray[5])! } func isCorrect() -> Bool{ if correctAnswerNumber == userChoiceAnswerNumber{ return true } return false } } class QuestionDataManager{ static let sharedInstance = QuestionDataManager() var questionDataArray = [QuestionData]() var nowQuestionIndex: Int = 0 private init(){ } func loadQuestion(){ questionDataArray.removeAll() nowQuestionIndex = 0 guard let csvFilePath = Bundle.main.path(forResource: "question", ofType: "csv") else { print("csvファイルが存在しません") return } do { let csvStringData = try String(contentsOfFile: csvFilePath, encoding: String.Encoding.utf8) csvStringData.enumerateLines(invoking:{ (line, stop) in let questionSourceDataArray = line.components(separatedBy: ",") let questionData = QuestionData (questionSourceDataArray: questionSourceDataArray) self.questionDataArray.append(questionData) questionData.questionNo = self.questionDataArray.count }) } catch let error{ print("csvファイル読み込みエラーが発生しました:(error)") return } } func nextQuestion() -> QuestionData? { if nowQuestionIndex < questionDataArray.count { let nextQuestion = questionDataArray[nowQuestionIndex] nowQuestionIndex += 1 return nextQuestion } return nil } }

試したこと

読み込み部分のコードでおかしい部分がないか確認しましたが間違えていないと思います。。

https://yutahand.com/coffeequiz/

またこのブログを参考に自分でナンバーを設定もしたのですおなじようなエラーが出てしまいます。
またこのブログではバグと書いてあり、再起動で治ると書いてありましたが再起動しても治りませんでした。

補足情報(FW/ツールのバージョンなど)

swift 3
xcode 8.2.1
参考にしている本:本気ではじめるiPhoneアプリ作り 黒帯エンジニアがしっかり教える基本テクニック Xcode8.X+Swift3.X対応

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

現在viewDidLoad()内に書かれている処理を含めて、questionDataへのアクセスはquestionDataの読み込みが完了してから実行するようにして下さい。

投稿2018/12/07 08:10

編集2018/12/07 08:39
fuzzball

総合スコア16731

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

oilfriedchicken

2018/12/07 08:23

回答ありがとうございます! 問題画面のコードをすべて載せられていなかったため修正いたしました。 questionNoLabelは繋いでいます。
fuzzball

2018/12/07 08:27

エラーが出る行の上に print(questionNoLabel) を追加して、その出力を書いて下さい。
oilfriedchicken

2018/12/07 08:30

<UILabel: 0x7fc102e09330; frame = (16 20; 42 20.5); text = 'Q1'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x60800009c340>> と表示されました。
fuzzball

2018/12/07 08:39

回答を書き直しました。
oilfriedchicken

2018/12/08 15:53

再び回答ありがとうございます!読み込み後に実行する方法というのは初心者で実装するにはどのようにするのがおすすめでしょうか。 NSNotificationなどを利用して実装しようと考えたのですが挫折してしまいました。。。
guest

0

画面が表示されたときに、questionDataが空なようです。
可能性を考えてみたので、以下をチェックしてみてください。

question.csvは作成しましたか?
question.csvに一つ以上の問題が記入されていますか?
question.csvはプロジェクトに追加しましたか?
「csvファイルが存在しません」「csvファイル読み込みエラーが発生しました」というエラーはログに表示されていませんか?

投稿2018/12/07 09:19

ha1f

総合スコア83

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

oilfriedchicken

2018/12/08 01:22

回答ありがとうございます。 csvは作成して3つの問題が記入されており、プロジェクトに追加されていますね、ログも表示されていないです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問