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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Core Data

Core DataはAppleのOS X and iOSのためのオブジェクトモデリングと持続性を持ったフレームワークです。Xcodeはエンティティー、属性そして関係性を特定するためのオブジェクトモデルの編集機能を提供します。

Xcode

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

Swift

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

Q&A

解決済

1回答

493閲覧

CoreDataを使ってデータを保存する際、前画面から値が引き渡された場合とそうでない場合の場合分けをしたい

lilybelly

総合スコア19

Core Data

Core DataはAppleのOS X and iOSのためのオブジェクトモデリングと持続性を持ったフレームワークです。Xcodeはエンティティー、属性そして関係性を特定するためのオブジェクトモデルの編集機能を提供します。

Xcode

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

Swift

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

0グッド

0クリップ

投稿2019/02/18 15:44

はじめに

初めまして。swiftを勉強して二ヶ月ほどの初心者です。
今回勉強がてら簡単なメモアプリを作成しているんですが、データ保存にcoreDataを使ってみたところ
なかなかうまくいかなくなってしまったのでご教授願いします。

##メモアプリの概要
就活生用のエントリーシートメモアプリを作成しています。
保存するデータは

  • メモのタイトル
  • 企業名
  • 提出期限名
  • メモテキスト
  • テキストの文字数

です。

CoreDataも以下のように設定しました。
イメージ説明

##困っている部分
メモの新規作成の場合と編集の場合を、前の画面から引き渡された値があるかないかで場合分けしたいのですが、うまくできません。

##該当するコード

swift4

1// 2// ViewController.swift 3 4 5import UIKit 6import CoreData 7 8class ViewController: UIViewController, UITextFieldDelegate,UITextViewDelegate { 9 10 @IBOutlet var titleField: UITextField! 11 @IBOutlet var memoTextView: UITextView! 12 @IBOutlet var memoNumLabel: UILabel! 13 @IBOutlet var companyField: UITextField! 14 @IBOutlet var dateField: UITextField! 15 16 //coreData 17 var memo:Memo? 18 19 //UIDatePickerを定義するための変数 20 var datePicker: UIDatePicker = UIDatePicker() 21 22 var context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext 23 24 //画面が呼ばれる前 25 override func viewDidAppear(_ animated: Bool) { 26 super.viewWillAppear(animated) 27 print(memo) 28 } 29 30 @IBAction func tapScreen(_ sender: Any) { 31 self.view.endEditing(true) 32 } 33 //画面が呼ばれた時 34 override func viewDidLoad() { 35 super.viewDidLoad() 36 titleField.delegate = self 37 memoTextView.delegate = self 38 companyField.delegate = self 39 dateField.delegate = self 40 41 if let memo = memo { 42 editedMemo(memo) 43 } 44 45 // ピッカー設定 46 datePicker.datePickerMode = UIDatePicker.Mode.dateAndTime 47 datePicker.timeZone = NSTimeZone.local 48 datePicker.locale = Locale.current 49 dateField.inputView = datePicker 50 51 // 決定バーの生成 52 let toolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 35)) 53 let spacelItem = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil) 54 let doneItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: Selector(("doneBtn"))) 55 toolbar.setItems([spacelItem, doneItem], animated: true) 56 57 // インプットビュー設定(紐づいているUITextfieldへ代入) 58 dateField.inputView = datePicker 59 dateField.inputAccessoryView = toolbar 60 //キーボードを閉じる 61 view.endEditing(true) 62 } 63 64 // UIDatePickerのDoneを押したら発火 65 @objc func doneBtn() { 66 dateField.endEditing(true) 67 68 // 日付のフォーマット 69 let formatter = DateFormatter() 70 71 //"yyyy年MM月dd日"を"yyyy/MM/dd"したりして出力の仕方を好きに変更できる 72 formatter.dateFormat = "yyyy年MM月dd日H時" 73 74 //(from: datePicker.date))を指定してあげることで 75 //datePickerで指定した日付が表示される 76 dateField.text = "(formatter.string(from: datePicker.date))" 77 78 } 79 80 //入力ごとに文字数をカウントする 81 func textViewDidChange(_ textView: UITextView) { 82 let commentNum = memoTextView.text.count 83 memoNumLabel.text = String(commentNum) 84 } 85 86 func editedMemo(_ memo:Memo){ 87 //編集用に表示 88 titleField.text = memo.title 89 companyField.text = memo.company 90 memoTextView.text = memo.memoText 91 memoNumLabel.text = memo.memoNum 92 dateField.text = memo.memoDate 93 94 } 95 96 @IBAction func saveMemo(_ sender: Any) { 97 //alertの設定 98 let alert: UIAlertController = UIAlertController(title: "メモの登録", message: "この内容で保存しますか?", preferredStyle: UIAlertController.Style.alert) 99 100 // キャンセルボタン 101 let cancelAction: UIAlertAction = UIAlertAction(title: "キャンセル", style: UIAlertAction.Style.cancel, handler:{ 102 // ボタンが押された時の処理を書く(クロージャ実装) 103 (action: UIAlertAction!) -> Void in 104 print("Cancel") 105 }) 106 107 108 // OKボタン押下時のイベント 109 let okAction = UIAlertAction(title: "OK", style: .default) { (action) in 110 111 let editTitle = self.titleField.text 112 let editCompany = self.companyField.text 113 let editText = self.memoTextView.text 114 let editNum = self.memoNumLabel.text 115 let editDate = self.dateField.text 116 117 118 if self.memo == nil { 119 let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext 120 self.memo = Memo(context: context) 121 } 122 123 if let memo = self.memo{ 124 // context(データベースを扱うのに必要)を定義。 125 let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext 126 127 let appDelegate = UIApplication.shared.delegate as! AppDelegate 128 let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Memo") 129 let predicate = NSPredicate(format: "title = %@ and company = %@ and memoText = %@ and memoNum = %@ and memoDate = %@", memo.title!, memo.company!, memo.memoText!, memo.memoNum!, memo.memoDate!) 130 fetchRequest.predicate = predicate 131 132 do { 133 let memo = try context.fetch(fetchRequest) 134 let memoData:Memo = memo[0] as! Memo 135 memoData.title = self.titleField.text 136 memoData.company = self.companyField.text 137 memoData.memoText = self.memoTextView.text 138 memoData.memoNum = self.memoNumLabel.text 139 memoData.memoDate = self.dateField.text 140 141 } catch let error as NSError { 142 print(error) 143 } 144 145 } 146 147 // 上で作成したデータをデータベースに保存 148 (UIApplication.shared.delegate as! AppDelegate).saveContext() 149 150 self.dismiss(animated: true, completion: nil) 151 152 //入力値をクリアにする 153 self.clearData() 154 } 155 156 func didReceiveMemoryWarning() { 157 super.didReceiveMemoryWarning() 158 } 159 160 alert.dismiss(animated: true, completion: nil) 161 162 // ③ UIAlertControllerにActionを追加 163 alert.addAction(cancelAction) 164 alert.addAction(okAction) 165 166 // ④ Alertを表示 167 present(alert, animated: true, completion: nil) 168 169 } 170 // 入力値をクリア 171 func clearData() { 172 titleField.text = "" 173 companyField.text = "" 174 memoTextView.text = "" 175 memoNumLabel.text = "0" 176 dateField.text = "" 177 } 178 179 func textFieldShouldReturn(_ textField: UITextField) -> Bool { 180 //キーボードを隠す 181 textField.resignFirstResponder() 182 return true 183 } 184 185 func applicationWillTerminate(_ application: UIApplication) { 186 self.saveContext() 187 } 188 //データを保存 189 func saveContext () { 190 191 let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext 192 if context.hasChanges { 193 do { 194 try context.save() 195 print(context) 196 } catch { 197 let nserror = error as NSError 198 fatalError("Unresolved error (nserror), (nserror.userInfo)") 199 } 200 } 201 } 202} 203 204

##エラー内容
「Unexpectedly found nil while unwrapping an Optional value」
と言われます。

きっと

if self.memo == nil { let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext self.memo = Memo(context: context) }

の部分でmemoに値が代入されるために
次のコード

swift

1if let memo = self.memo{ 2 // context(データベースを扱うのに必要)を定義。 3 let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext 4 5 let appDelegate = UIApplication.shared.delegate as! AppDelegate 6 let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Memo") 7 let predicate = NSPredicate(format: "title = %@ and company = %@ and memoText = %@ and memoNum = %@ and memoDate = %@", memo.title!, memo.company!, memo.memoText!, memo.memoNum!, memo.memoDate!) 8 fetchRequest.predicate = predicate 9//以下省略 10

の部分が通れてしまっているのが原因だと考えています。
そこで if{}を2つ並べるのではなく、
if{}else{}としてみたものの新たなエラーがでます。

swift

1 if self.memo == nil { 2 let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext 3 self.memo = Memo(context: context) 4 5 }else{ 6 let memo = self.memo 7 // context(データベースを扱うのに必要)を定義。 8 let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext 9 10 let appDelegate = UIApplication.shared.delegate as! AppDelegate 11 let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Memo") 12 let predicate = NSPredicate(format: "title = %@ and company = %@ and memoText = %@ and memoNum = %@ and memoDate = %@", memo.title!, memo.company!, memo.memoText!, memo.memoNum!, memo.memoDate!) 13 fetchRequest.predicate = predicate 14 15 do { 16 let memo = try context.fetch(fetchRequest) 17 let memoData:Memo = memo[0] as! Memo 18 memoData.title = self.titleField.text 19 memoData.company = self.companyField.text 20 memoData.memoText = self.memoTextView.text 21 memoData.memoNum = self.memoNumLabel.text 22 memoData.memoDate = self.dateField.text 23 24 } catch let error as NSError { 25 print(error) 26 } 27 28 } 29

と変更すると、
イメージ説明
というエラーがでてしまい、これを解決することもできずに行き詰まってしまっています、、、。

どうにか助けていただきたいです。よろしくお願いします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

考え方から変えましょう。

あなたは保存するときにはじめて新規作成だった時に空のMemoを生成しようとしていますが、ビューが表示されるときにやってしまいましょう。

例えばこうです

swift

1 2override func viewDidLoad() { 3 ... 4 ... 5 // 削除 6// if let memo = memo { 7// editedMemo(memo) 8// } 9 10 // メモがなければ新規作成 11 if memo == nil { 12 let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext 13 memo = Memo(context: context) 14 } 15 16 // メモの値を表示。 17 editedMemo(memo)

こうしておけば、保存時に新規作成か編集かの判定をする必要はなく、単にmemoの保存処理だけをすればよいようになります。

投稿2019/02/19 00:17

MasakiHori

総合スコア3384

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

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

lilybelly

2019/02/25 18:34

無事解決しました!ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問