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

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

新規登録して質問してみよう
ただいま回答率
85.48%
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

解決済

3回答

511閲覧

signal SIGABRT というエラー

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/25 18:49

編集2019/03/10 09:42

前提・実現したいこと

メモアプリを作成中ですが、エラーが解決できずに困っています。
coreDataを使ってセクション分けをしたいです。

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

Thread 1: signal SIGABRT //デバッグメッセージ Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'keypath company not found in entity <NSSQLEntity Memo id=1>'

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

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

です。
この中の企業名companyを使ってセクション分けをしたいです。

該当のソースコード

swift

1 2import UIKit 3import CoreData 4 5 6class MemoTableViewController: UITableViewController, UINavigationControllerDelegate, NSFetchedResultsControllerDelegate { 7 8 //配列作成(coreData) for tableView 9 var memoData:[Memo] = [] 10 11 var fetchedResultsController: NSFetchedResultsController<NSFetchRequestResult>! 12 13 let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext 14 15 var fetchedResultController:NSFetchedResultsController<NSFetchRequestResult>! 16 17 override func viewDidLoad() { 18 super.viewDidLoad() 19 20 // 編集ボタンを左上に配置 21 navigationItem.leftBarButtonItem = editButtonItem 22 editButtonItem.tintColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0) 23 24 //編集中のセル選択を許可 25 tableView.allowsSelectionDuringEditing = true 26 27 tableView.reloadData() 28 } 29 30 override func viewWillAppear(_ animated: Bool) { 31 super.viewWillAppear(animated) 32 getData() 33 //配列が追加した後もういちどデータをリロードさせる 34 tableView.reloadData() 35 fetchedResultsController = createFetchedResultsController() 36 37 } 38 39 func getData() { 40 // データ保存時と同様にcontextを定義 41 let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext 42 43 do { 44 // CoreDataからデータをfetchしてtasksに格納 45 let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Memo") 46 fetchRequest.returnsObjectsAsFaults = false 47 48 memoData = try context.fetch(fetchRequest) as! [Memo] 49 50 } catch { 51 print("Fetching Failed.") 52 } 53 } 54 func createFetchedResultsController() -> NSFetchedResultsController<NSFetchRequestResult> { 55 let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Memo") 56 fetchRequest.returnsObjectsAsFaults = false 57 58 //セクションをcompanyごとにまず並び替える 59 fetchRequest.sortDescriptors = [ 60 NSSortDescriptor(key: "company", ascending: true) 61 ] 62 63 let entity = NSEntityDescription.entity(forEntityName: "Memo", in: context) 64 fetchRequest.entity = entity 65 //ソートキーの指定。セクションが存在する場合セクションに対応した属性を必ず最初に指定する 66 let companySortDescriptor = NSSortDescriptor(key: "company", ascending: true) 67 //セクション内は作成日時順 68 let dataSortDescriptor = NSSortDescriptor(key: "createdAt", ascending: true) 69 fetchRequest.sortDescriptors = [companySortDescriptor, dataSortDescriptor] 70 71 //セクションの名前として"publisher"を指定(fetchRequestの初期化) 72 let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: "company", cacheName: nil) 73 fetchedResultsController.delegate = self 74 75 do { 76 try fetchedResultsController.performFetch() 77 } catch { 78 abort() 79 } 80 return fetchedResultsController 81 } 82 83 // MARK: - Table View 84 func numberOfSectionsInTableView(tableView: UITableView) -> Int { 85 //セクション数を返す 86 return fetchedResultsController.sections?.count ?? 0 87 } 88 89 90 91 func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { 92 //セクション名を返す 93 let sectionInfo = fetchedResultsController.sections![section] 94 return sectionInfo.name 95 } 96 97// セルの作成 98 func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 99 //セクション内のオブジェクトの数を返す 100 let sectionInfo = fetchedResultsController.sections![section] 101 return sectionInfo.numberOfObjects 102 } 103 104 //セルの作成 rowは何行目か 105 override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 106 let cell = tableView.dequeueReusableCell(withIdentifier: "MemoTitleTableViewCell", for: indexPath) 107 configureCell(cell: cell, object: fetchedResultsController.object(at: indexPath)) 108 return cell 109 110 } 111 112 func configureCell(cell: UITableViewCell, object: AnyObject) { 113 let memo = object as! Memo 114 cell.textLabel?.text = memo.title 115 cell.detailTextLabel?.text = memo.memoNum 116 } 117 118 119 //セルの削除 120 override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { 121 let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext 122 123 if editingStyle == .delete { 124 // 削除したいデータのcategoryとnameを取得 125 let deletedMemoData = memoData[indexPath.row] 126 127 do { 128 context.delete(deletedMemoData) 129 memoData.remove(at: indexPath.row) 130 } catch { 131 print("Fetching Failed.") 132 } 133 134 // 削除したあとのデータを保存する 135 (UIApplication.shared.delegate as! AppDelegate).saveContext() 136 137 // 削除後の全データをfetchする 138 getData() 139 } 140 // taskTableViewを再読み込みする 141 tableView.reloadData() 142 } 143 144 //セルを選択した時に実行 145 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 146 self.performSegue(withIdentifier: "showDetail", sender: self) 147 } 148 149//編集 150 override func setEditing(_ editing: Bool, animated: Bool) { 151 super.setEditing(editing, animated: animated) 152 tableView.isEditing = editing 153 } 154 155//画面遷移で値を引き渡す 156 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 157 guard let identifier = segue.identifier else { 158 return 159 } 160 switch identifier { 161 case "showDetail": 162 //渡したい値を設定する 163 let indexPath = tableView.indexPathForSelectedRow 164 // segueから遷移先のNavigationControllerを取得(画面遷移) 165 let nc = segue.destination as! UINavigationController 166 // NavigationControllerの一番目のViewControllerが次の画面 167 let vc = nc.topViewController as! DetailViewController 168 // contextをAddTaskViewController.swiftのcontextへ渡す 169 let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext 170 vc.context = context 171 172 //indexPathがnilでないことを確認し、選択した行のデータを引きわたす 173 174 if let indexPath = indexPath{ 175 vc.detailData = self.memoData[indexPath.row] 176 } 177 178 179 default: 180 fatalError("Unknow segue: (identifier)") 181 } 182 } 183} 184 185

ちなみにエラー解決のために思考錯誤中に、subclassのデータも作成しました

//Memo+CoreDataClass.swift @objc(Memo) public class Memo: NSManagedObject { @NSManaged public var company: String? @NSManaged public var createdAt: NSDate? @NSManaged public var memoDate: String? @NSManaged public var memoNum: String? @NSManaged public var memoText: String? @NSManaged public var title: String? @objc var sectionDate: String { let dateFormatter = DateFormatter() dateFormatter.locale = NSLocale(localeIdentifier: "en_US") as Locale! dateFormatter.dateFormat = "yyyy/MM/dd" return dateFormatter.string(from: self.createdAt! as Date) } }
//Memo+CoreDataProperties.swift extension Memo { @nonobjc public class func fetchRequest() -> NSFetchRequest<Memo> { return NSFetchRequest<Memo>(entityName: "Memo") } @NSManaged public var company: String? @NSManaged public var createdAt: NSDate? @NSManaged public var memoDate: String? @NSManaged public var memoNum: String? @NSManaged public var memoText: String? @NSManaged public var title: String? }

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

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

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

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

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

guest

回答3

0

私は、MemoTableViewControllerの他に、company と title を入力する画面を用意しました。(ここでは、memoNum等は省略しています)
Xcodeは、Version 10.1でdeployment target は iOS 12.1です。

swift

1import UIKit 2import CoreData 3 4class ViewController: UIViewController { 5 6 @IBOutlet var myTextField:UITextField! 7 @IBOutlet var myTitle:UITextField! 8 @IBOutlet var nyuryokuButton:UIButton! 9 10 let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext 11 12 override func viewDidLoad() { 13 super.viewDidLoad() 14 myTextField.becomeFirstResponder() 15 } 16 17 @IBAction func myActionNyuryokuKanryo(){ 18 guard let i = myTextField.text, !(i.isEmpty), let j = myTitle.text, !(j.isEmpty) else {return} 19 let memo = Memo(context: context) 20 memo.company = i 21 memo.title = j 22 memo.createdAt = Date() 23 (UIApplication.shared.delegate as! AppDelegate).saveContext() 24 performSegue(withIdentifier: "toTableView", sender: true) 25 } 26 27} 28

投稿2019/03/14 13:34

BMJr

総合スコア80

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

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

0

ベストアンサー

コードの一部を書き換えたらうまく行きました。
以下に変更前と変更後を示します。
func を override func に変えて、numberOfSectionsInTableView(tableView: UITableView) を numberOfSections(in tableView: UITableView) に変更し、{ } の中身にif fetchedResultsController == nil {return 0} を加えました。

変更前

swift

1func numberOfSectionsInTableView(tableView: UITableView) -> Int { 2 //セクション数を返す 3 return fetchedResultsController.sections?.count ?? 0 4 } 5 6 7 8 func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { 9 //セクション名を返す 10 let sectionInfo = fetchedResultsController.sections![section] 11 return sectionInfo.name 12 } 13 14// セルの作成 15 func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 16 //セクション内のオブジェクトの数を返す 17 let sectionInfo = fetchedResultsController.sections![section] 18 return sectionInfo.numberOfObjects 19 }

変更後

swift

1override func numberOfSections(in tableView: UITableView) -> Int { 2 //セクション数を返す 3 if fetchedResultsController == nil{ 4 return 0 5 } 6 else{ 7 return fetchedResultsController.sections?.count ?? 0 8 } 9 } 10 11 override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { 12 //セクション名を返す 13 let sectionInfo = fetchedResultsController.sections![section] 14 return sectionInfo.name 15 } 16 17 // セルの作成 18 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 19 //セクション内のオブジェクトの数を返す 20 let sectionInfo = fetchedResultsController.sections![section] 21 return sectionInfo.numberOfObjects 22 }

投稿2019/03/13 05:42

BMJr

総合スコア80

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

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

lilybelly

2019/03/14 12:15

回答していただいたコードで試してみたんですが、 エラーは起こらずにビルドできるものの、テーブルにデータが表示されなくなりました。 原因は変更した if fetchedResultsController == nil{ return 0 } の部分のように思われます。 fetchedResultsControllerを生成するcreateFetchedResultsController()が間違っているのでしょうか。 必要でしたらgithubのURLを送らせていただきます。
BMJr

2019/03/14 13:29

ご返信ありがとうございます。 当初は、 if fetchedResultsController == nil{ return 0 } を入れていなかったのですが、そうすると、 「Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value」 というエラーメッセージとともにクラッシュしたため、上記の1行を加えました。 createFetchedResultsController() の部分は、ご提示いただいたコードのままです。 私は、MemoTableViewControllerの他に、company と title を入力する画面を用意しました。回答欄に入力画面のコードを提示いたします。
BMJr

2019/03/14 15:31

追伸: fetchedResultsController = createFetchedResultsController() の1文をoverride func viewDidLoad() 内に記載したところ、 if fetchedResultsController == nil{ return 0 } がなくてもエラーが出なくなりました。
lilybelly

2019/03/17 05:24

ご回答ありがとうございます! 今日コードはこのままでもう一度ビルドしてみたら、なぜかうまく表示されました。 前回ご指摘いただいた fetchedResultsController = createFetchedResultsController() の1文をoverride func viewDidLoad() 内に記載し、 if fetchedResultsController == nil{ return 0 } を指示通り削除すると 「 Fatal error: Unexpectedly found nil while unwrapping an Optional value」がでるので、 やはり最初にBMJrさんがおっしゃっていた方法でよかったように思います。 お手数をおかけして申し訳ありませんでした。 こちらの回答をベストアンサーにさせていただきます。 ご丁寧に対応していただきありがとうございまいした。 今後ともよろしくお願いします。
BMJr

2019/03/18 12:27

うまくいってよかったです。 私も、NSFetchedResultsControllerという便利な機能を知ることができて勉強になりました。
guest

0

Entity が 「Memo」 で、Memo 内の Attributes に
company (Type: String) や createdAt (Type: Date) が含まれるとすると、company の個数と createdAt の個数は正確に一致する(1:1対応する)ことになりますが、上記のコードでは一つの company 内に複数の作成日時が含まれるように見えます。この辺りがエラーの原因ではないでしょうか。あるいは、ご質問の本文中で「Company」と"C"が大文字になっていましたが、コード内では「company」と"c"が小文字になっていることが気になりました。

投稿2019/03/09 14:31

BMJr

総合スコア80

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

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

lilybelly

2019/03/10 09:41

ご回答ありがとうございます。 こちらの説明不足で申し訳ありません。 例えば「Memo(1つ目): company:三菱地所 , createdAt:2019/03/03/11:28』「Memo(2つ目): company:三菱地所 , createdAt:2019/02/03/11:40」といったように同じcompany名のデータがいくつか入ることを想定して、company名でまとめてセクション分けをしたいと考えております。 なのでcompany の個数と createdAt の個数は正確に一致するようにはなってるとおもうんですが、この場合セクション分けをすることは出来ないのでしょうか。ご教授していただきたいです。 質問の本文中で「Company」と"C"が大文字になっていることについては、 記載ミスなので編集させていただきます。 ご指摘ありがとうございます。
BMJr

2019/03/10 15:17

了解致しました。 ご提示されたコードを自分のXcodeにコピペしてみました。エラーは出ませんでしたが、titleがtableView cellに表示されませんでした。私もNSFetchedResultsControllerの扱いに習熟しておりませんので、うまく原因が分かりません。申し訳ございません・・・。また、何か分かりましたら、回答に追加させていただきます。
lilybelly

2019/03/11 14:24

ご丁寧にありがとうございます! 私もわかり次第、解決方法を載せたいと思います。 アドバイスをくださりありがとうございました。今後ともよろしくお願いします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問