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

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

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

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

Q&A

解決済

1回答

2081閲覧

【swift5】Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

Kaguya_4869

総合スコア117

Swift

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

0グッド

1クリップ

投稿2020/02/16 08:48

編集2020/02/22 00:50

#質問したいこと
いつもお世話になっています。
現在、カメラを取り入れたメモアプリを作成中です。
起動させた時に

Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

というエラーが出てきます。
ただ一番最初の画面はViewControllerというところに作っていて、二つ目のファイルをsecondViewControllerというファイルで作っているのですが、エラーが出るのはなぜかsecondViewControllerの方です。

また落ちるところも2パターンあり、
①起動した時点で落ちる
②チュートリアル画面からホーム画面に行くところで落ちる
の2パターンあります。

その時エラー内容はどちらも

Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

です。
#コード

viewcontroller

1  //ホーム画面 2import UIKit 3 4 5 6class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate { 7 8 @IBOutlet weak var memoTableView: UITableView! 9 10// var memoArray = [String]() 11 12 let ud = UserDefaults.standard 13 14 let saveData: UserDefaults = UserDefaults.standard 15 16 var deleteNakami = [String]() 17 18 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 19 return MemonoNakami.count 20// return MemoImageNakami.count 21 } 22 23 24 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 25 let cell = tableView.dequeueReusableCell(withIdentifier: "memoCell", for: indexPath) 26 cell.textLabel?.text = MemonoNakami[indexPath.row] 27 return cell 28 } 29 30 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 31 self.performSegue(withIdentifier: "toDetail", sender: nil) 32 //押したら押した状態を解除 33 tableView.deselectRow(at: indexPath, animated: true) 34 } 35 36 37 override func viewDidLoad() { 38 super.viewDidLoad() 39 40 //追加画面で入力した内容を取得する 41 if UserDefaults.standard.object(forKey: "memoArray") != nil { 42 MemonoNakami = UserDefaults.standard.object(forKey: "memoArray") as! [String] 43 } 44 if UserDefaults.standard.object(forKey: "MemoImage") != nil{ 45// MemoImageNakami = UserDefaults.standard.object(forKey: "MemoImage") as! [UIImage] 46 MemoImageNakami = [ud.image(forKey: "MemoImage")] 47 48 } 49 memoTableView.delegate = self 50 memoTableView.dataSource = self 51 memoTableView.reloadData() 52 } 53 54 override func viewWillAppear(_ animated: Bool) { 55 loadMemo() 56 } 57 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 58 //destinationのクラッシュ防ぐ 59 if segue.identifier == "toDetail"{ 60 //detailViewControllerを取得 61 //as! DetailViewControllerでダウンキャストしている 62 let detailViewController = segue.destination as! DetailViewController 63 //遷移前に選ばれているCellが取得できる 64 let selectedIndexPath = memoTableView.indexPathForSelectedRow! 65 detailViewController.selectedMemo = MemonoNakami[selectedIndexPath.row] 66 detailViewController.selectedRow = selectedIndexPath.row 67 68 let selectedIndexPathImage = memoTableView.indexPathForSelectedRow! 69 detailViewController.selectedImageMemo = MemoImageNakami[selectedIndexPathImage.row] 70 print(MemoImageNakami.count) 71 } 72 } 73 func loadMemo(){ 74 if ud.array(forKey: "memoArray") != nil{ 75 //取得 またas!でアンラップしているのでnilじゃない時のみ 76 MemonoNakami = ud.array(forKey: "memoArray") as![String] 77 //reloadしてくれる 78 memoTableView.reloadData() 79 } 80 if ud.array(forKey: "MemoImage") != nil{ 81 82 MemonoNakami = ud.array(forKey: "memoArray") as! [String] 83 84 memoTableView.reloadData() 85 } 86 } 87 func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { 88 89 if editingStyle == .delete { 90// saveData.set(deleteNakami, forKey: "deleteMemo") 91 //resultArray内のindexPathのrow番目をremove(消去)する 92 MemonoNakami.remove(at: indexPath.row) 93 94 //再びアプリ内に消去した配列を保存 95 ud.set(MemonoNakami, forKey: "memoArray") 96 ud.set(MemonoNakami, forKey: "MemoImage") 97 98 //tableViewを更新 99 tableView.reloadData() 100 } 101 } 102}

secondViewcontroller

1import UIKit 2 3 4class secondViewcontroller: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate { 5 6 @IBOutlet weak var memoTextView: UITextView! 7 @IBOutlet weak var imageView: UIImageView! 8 9 var selectedRow: Int! 10 var selectedMemo : String! 11// var selectedImageRow: UIImage! 12 var selectedImageMemo: UIImage! 13 14 let saveData: UserDefaults = UserDefaults.standard 15 let ud = UserDefaults.standard 16 17 override func viewDidLoad() { 18 super.viewDidLoad() 19 memoTextView.text = selectedMemo 20 21 MemoImageNakami = [ud.image(forKey: "MemoImage")] 22 imageView.image = selectedImageMemo 23 24 let kbToolBar = UIToolbar(frame: CGRect(x: 0, y: 0, width: 320, height: 40)) 25 kbToolBar.barStyle = UIBarStyle.default // スタイルを設定 26 kbToolBar.sizeToFit() // 画面幅に合わせてサイズを変更 27 // スペーサー 28 let spacer = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: self, action: nil) 29 // 閉じるボタン 30 let commitButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.done, target: self, action: #selector(self.commitButtonTapped)) 31 kbToolBar.items = [spacer, commitButton] 32 memoTextView.inputAccessoryView = kbToolBar 33 34 35 } 36 37 @objc func commitButtonTapped() { 38 self.view.endEditing(true) 39 } 40 41 //画面遷移する時にタップするボタン(保存) 42 @IBAction func save(_ sender: Any) { 43 44 let inputText = memoTextView.text 45 let ud = UserDefaults.standard 46 if ud.array(forKey: "memoArray") != nil{ 47 //saveMemoArrayに取得 48 var saveMemoArray = ud.array(forKey: "memoArray") as! [String] 49 50 //テキストに何か書かれているか? 51 if inputText != ""{ 52 //配列に追加 53 saveMemoArray[selectedRow] = inputText! 54 ud.set(saveMemoArray, forKey: "memoArray") 55 }else{ 56 showAlert(title: "何も入力されていません") 57 58 } 59 60 }else{ 61 //最初、何も書かれていない場合 62 var newMemoArray = [String]() 63 //nilを強制アンラップはエラーが出るから 64 if inputText != ""{ 65 //inputtextはoptional型だから強制アンラップ 66 newMemoArray.append(inputText!) 67 ud.set(newMemoArray, forKey: "memoArray") 68 }else{ 69 showAlert(title: "何も入力されていません") 70 } 71 } 72 73 showAlert(title: "保存完了") 74 ud.synchronize() 75 } 76 77 func showAlert(title:String){ 78 let alert = UIAlertController(title: title, message: nil, preferredStyle: .alert) 79 80 alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) 81 82 alert.addAction(UIAlertAction(title: "キャンセル", style: .cancel, handler: nil)) 83 84 self.present(alert, animated: true, completion:nil) 85 } 86 //削除ボタン 87 @IBAction func deleteMemo(_ sender: Any) { 88 let ud = UserDefaults.standard 89 if ud.array(forKey: "memoArray") != nil{ 90 var saveMemoArray = ud.array(forKey: "memoArray") as![String] 91 saveMemoArray.remove(at: selectedRow) 92 ud.set(saveMemoArray, forKey: "memoArray" ) 93 ud.synchronize() 94 //画面遷移 95 self.navigationController?.popViewController(animated: true) 96 } 97 } 98 99 100 101 @IBAction func showActivityView(_ sender: UIBarButtonItem) { 102 let controller = UIActivityViewController(activityItems: [imageView.image!, memoTextView.text!], applicationActivities: nil) 103 self.present(controller, animated: true, completion: nil) 104 105 } 106 107} 108 109extension UserDefaults { 110 111 // 保存したいUIImage, 保存するUserDefaults, Keyを取得 112 func setUIImageToData(image: UIImage, forKey: String) { 113 // UIImageをData型へ変換 114 let nsdata = image.pngData() 115 // UserDefaultsへ保存 116 self.set(nsdata, forKey: "MemoImage") 117 } 118 119 // 参照するUserDefaults, Keyを取得, UIImageを返す 120 func image(forKey: String) -> UIImage { 121 // UserDefaultsからKeyを基にData型を参照 122 let data = self.data(forKey: "MemoImage") 123 // UIImage型へ変換 124 let returnImage = UIImage(data: data!) //ここでエラー発生!!!!!!!!! 125 // UIImageを返す 126 return returnImage! 127 } 128 129}

#やってみたこと
どこかの値がnilなのかなと思っているのですが見当たらず、接続も見直してみましたが正常でした。
#参考サイト
UIImageをUserDefaultsに保存するためのextensionを作った

#追記

Fatal error: Unexpectedly found nil while unwrapping an Optional value: file /Users/Kaguya_4869/Desktop/MemoApp/MemoApp/secondViewcontroller.swift, line 452

上記のコードだと、

swift

1// UIImage型へ変換 2 let returnImage = UIImage(data: data!)

の部分です(secondViewcontrollerのextensionの中です。)
よろしくお願いします。

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

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

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

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

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

hoshi-takanori

2020/02/16 09:14

カメラで撮影した画像をそのままのサイズで UserDefaults に保存してるのでしょうか? そういう非常識なことはマジでやめて欲しいです。
Kaguya_4869

2020/02/16 09:21

まだプログラミング初心者で、データの保存はUserDefaultsでしかやったことがありませんでした。 これが非常識とは知らず、使ってしまっていました。 本当に申し訳ありません。 UserDefaultsでもできるかなと思ったのですが… 他のサイトではいいものがあまりなく、どうすればいいのか迷っています。 具体的にどうすればいいのかご教授願えますでしょうか?
hoshi-takanori

2020/02/16 09:50

ちょっと言い過ぎましたね。別に怒ってるわけではないので、謝らなくても大丈夫です。 UserDefaults は確かに手軽に使えて便利なんですが、本来は最後に開いていた画面はどれだったかとか、ちょっとした設定内容なんかを覚えておくためのものです。 「カメラを取り入れたメモアプリ」とのことで、画像は個別のファイルで、メモはなんらかのデータベース的なものに保存するのが一般的だと思いますが、初心者にはちょっと大変かもしれませんね…。
eytyet

2020/02/16 10:40

コンソールにでているエラーメッセージが、どこの値がnilなのかを知る大事な手がかりです。それを示していただけますか。
Kaguya_4869

2020/02/16 12:02

@hoshi-takanori 丁寧な回答ありがとうございます。 メモをデータベースに保存して、画像は個別に保存する方法試してみたいと思います。
Kaguya_4869

2020/02/16 12:03

@eytyet 追記しておきました。 よろしくお願いします。
guest

回答1

0

ベストアンサー

エラーの発生する行にブレークポイントを置いて、とめて何がnilなのか調べていくと原因を見つけられるようになると思います。

let returnImage = UIImage(data: data!)でnilなのは、dataしかないです。

dataがnilになるのは、UserDefault.data(forKey: "MemoImage")がnilを返すからですが、その理由はいくつか考えられますね。コードを読んだだけではちょっとわかりませんでした。
ViewControllerからは、array(forKey:)で同じキーの値にアクセスしているようなので、単にdata型じゃないのではありませんか。setUIImageToDataを使っている様子もありませんし。
いずれにしても、ブレークしながら何が読めているかを調べたりして、原因を調査してみてください。

投稿2020/02/16 12:12

eytyet

総合スコア803

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

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

Kaguya_4869

2020/02/19 09:44

返信が遅くなり、申し訳ございません。 わかりやすい回答ありがとうございます。 解決できました。 本当にありがとうございました。
TsukubaDepot

2020/02/19 10:57

質問者さん、 この質問に興味を持っています。 もしよかったら、「どのように解決」させたのか、具体的に書いていただけると助かります。
Kaguya_4869

2020/02/22 00:50

//追加画面 import UIKit import SwiftyTesseract var MemonoNakami = [String]() var MemoImageNakami = [UIImage]() class AddViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate { @IBOutlet weak var memoTextView: UITextView! @IBOutlet weak var imageView: UIImageView! // @IBOutlet weak var imageButton: UIButton! let swiftyTesseract = SwiftyTesseract(language: RecognitionLanguage.japanese) let saveData: UserDefaults = UserDefaults.standard //カメラボタンがタップされた時の処理 @IBAction func launchCamera(_ sender: UIButton) { let camera = UIImagePickerController.SourceType.camera if UIImagePickerController.isSourceTypeAvailable(camera) { let picker = UIImagePickerController() picker.sourceType = camera picker.delegate = self self.present(picker, animated: true) } imageView.isHidden = false // imageButton.isHidden = true } //アルバムから写真を選択 // @IBAction func openAlbum() { // //カメラロールを使えるかの確認 // if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) { // // //カメラロールの画像を選択して画像を表示するまでの一連の流れ // let picker = UIImagePickerController() // picker.sourceType = .photoLibrary // picker.delegate = self // // picker.allowsEditing = true // // // present(picker, animated: true, completion: nil) // } // } // //カメラロールから写真を選択する処理 @IBAction func choosePicture() { // カメラロールが利用可能か? if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) { // 写真を選ぶビュー let pickerView = UIImagePickerController() // 写真の選択元をカメラロールにする // 「.camera」にすればカメラを起動できる pickerView.sourceType = .photoLibrary // デリゲート pickerView.delegate = self // ビューに表示 self.present(pickerView, animated: true) } } //ユーザーが撮影し終わった時の処理 func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { let image = info[UIImagePickerController.InfoKey.originalImage] as! UIImage self.imageView.image = image UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil) self.dismiss(animated: true) UserDefaults.standard.set(image.jpegData(compressionQuality: 0.8), forKey: "MemoImage") saveData.synchronize() } override func viewDidLoad() { super.viewDidLoad() // donebuttonの実装 let kbToolBar = UIToolbar(frame: CGRect(x: 0, y: 0, width: 320, height: 40)) kbToolBar.barStyle = UIBarStyle.default // スタイルを設定 kbToolBar.sizeToFit() // 画面幅に合わせてサイズを変更 // スペーサー let spacer = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: self, action: nil) // 閉じるボタン let commitButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.done, target: self, action: #selector(self.commitButtonTapped)) kbToolBar.items = [spacer, commitButton] memoTextView.inputAccessoryView = kbToolBar //first image imageView.image = UIImage(named: "No-Image.PNG") } @objc func commitButtonTapped() { self.view.endEditing(true) } @IBAction func save(_ sender: Any) { let inputText = memoTextView.text let ud = UserDefaults.standard var addImage: UIImage = imageView.image! ud.setUIImageToData(image: addImage, forKey: "MemoImage") if ud.array(forKey: "memoArray") != nil{ var saveMemoArray = ud.array(forKey: "memoArray") as! [String] if inputText != ""{ //配列に追加 saveMemoArray.append(inputText!) ud.set(saveMemoArray, forKey: "memoArray") }else{ showAlert(title: "何も入力されていません") } }else{ var newMemoArray = [String]() if inputText != ""{ newMemoArray.append(inputText!) ud.set(newMemoArray, forKey: "memoArray") }else{ showAlert(title: "何も入力されていません") } } showAlert(title: "保存完了") ud.synchronize() } func showAlert(title:String){ let alert = UIAlertController(title: title, message: nil, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) alert.addAction(UIAlertAction(title: "キャンセル", style: .cancel, handler: nil)) self.present(alert, animated: true, completion:nil) } @IBAction func loadimageView() { print("読み込み開始") swiftyTesseract.performOCR(on: imageView.image!) { recognizedString in guard let text = recognizedString else { return } print("(text)") self.memoTextView.text = text } } } extension UserDefaults { // 保存したいUIImage, 保存するUserDefaults, Keyを取得 func setUIImageToData(image: UIImage, forKey: String) { // UIImageをData型へ変換 let nsdata = image.pngData() // UserDefaultsへ保存 self.set(nsdata, forKey: "memoImageArray") } // 参照するUserDefaults, Keyを取得, UIImageを返す func image(forKey: String) -> UIImage { // UserDefaultsからKeyを基にData型を参照 let data = self.data(forKey: forKey) // UIImage型へ変換 let returnImage = UIImage(data: data!) // UIImageを返す return returnImage! } }
Kaguya_4869

2020/02/22 00:52

こちらがメモの追加画面になっています。 今まで、 var addImage: UIImage = imageView.image! ud.setUIImageToData(image: addImage, forKey: "MemoImage") と extensionの部分がコメントアウトされていました。
Kaguya_4869

2020/02/22 00:52

長文失礼いたしました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問