前提
SwiftUIで以下のような明細欄を作っています。
| 商品 | 列2 | 列3 |
|---|---|---|
| 鉛筆 | A | B |
| 消しゴム | C | D |
| りんご | E | F |
| ノート | G | H |
商品,列2,列3以外はTextFieldです。
こちらの記事を参考に、
明細欄の商品列のデータ(鉛筆, ...ノート)を保存したいのですが、保存できませんでした。
CoreData
ENTITIES : DetailTable
Attributes : detailList(Binary Data)
カスタムクラス
Detail.swift
1import Foundation 2 3// Detail(明細)クラス定義 4class Detail: NSObject, NSCoding { 5 var ID = UUID() 6 var productName = "" 7 8 init(productName: String?) { 9 self.productName = productName! 10 } 11 12 func encode(with aCoder: NSCoder) { 13 aCoder.encode(self.productName, forKey: "productName") 14 } 15 16 required init?(coder aDecoder: NSCoder) { 17 self.productName = aDecoder.decodeObject(forKey: "productName") as! String 18 } 19}
データの保存
CreateView.swift
1struct CreateView: View { 2 @Environment(\.managedObjectContext) private var viewContext 3 @State var detailField = ["", ""] 4 ... 5 var body: some View { 6 ... 7 } 8// 保存ボタン押下時の処理 9 private func createEstimate() { 10 let detail = DetailTable(context: viewContext) 11 12// 明細情報の保存 13 let detailFields = detailField // 配列[鉛筆, 消しゴム, りんご, ノート] 14 @State var detailList = [] 15 for i in 0..<detailFields.count { 16 let detail = Detail(productName: detailFields[i]) 17 detailList.append(detail) 18 } 19 do { 20 let detailListData: Data = try NSKeyedArchiver.archivedData(withRootObject: detailList, requiringSecureCoding: false) as Data 21 22 detail.detailList = detailListData 23 24 } catch let error { 25 print(error.localizedDescription) 26 } 27 28 // 生成したインスタンスをCoreDataに保存する 29 do { 30 try viewContext.save() 31 print("保存成功") 32 } catch { 33 let nsError = error as NSError 34 fatalError("Unresolved error \(nsError), \(nsError.userInfo)") 35 } 36 37 presentation.wrappedValue.dismiss() 38 } 39}
実現したいこと
・カスタムクラスへデータを保存したいです。
発生している問題・エラーメッセージ
エラーメッセージはありません。
該当のソースコード
CreateView.swift
1// 保存ボタン押下時の処理 2 private func createEstimate() { 3 let detail = DetailTable(context: viewContext) 4 5// 明細情報の保存 6 let detailFields = detailField // 配列[鉛筆, 消しゴム, りんご, ノート] 7 @State var detailList = [] 8 for i in 0..<detailFields.count { 9 let detail = Detail(productName: detailFields[i]) 10 detailList.append(detail) 11 }
試したこと
print()を使い、値が出力されているか試しました。
- 配列detailListには値が追加されていませんでした。
- 配列detailFieldsには値が追加されていました。
- detailにも値は入っていました。しかし、以下のような同じ値でした。
detail結果
<ProjectName.Detail: 0x600000ec46f0>
<ProjectName.Detail: 0x600000e63210>
<ProjectName.Detail: 0x600000e63210>
<ProjectName.Detail: 0x600000e63210>
補足情報(FW/ツールのバージョンなど)
macOS Monterey バージョン 12.3
Swift version 5.6.1
Xcode バージョン 13.4.1
たくさん調べたのですが解決できませんでした。
お力添えいただけますととても嬉しく思います。
よろしくお願いいたします。
Core Dataは
レコード(行?)ごとに保存するのが一般的なのかな?と思うのですが、
(質問欄の例で言うと「鉛筆」「消しゴム」「りんご」「ノート」の4レコード)
1行にすべてのデータを保存しようとしているように見えます。
これには何か理由があるのでしょうか?
*Core Dataを使用する意味があまりないように見えまして、普通のファイルでも良いのかな?と思いましたので確認してみました
コメントくださり、ありがとうございます。
私がリレーションシップを使ったCore Dataへの保存と呼び出しをできなかったのが理由になります。
特に
①概要テーブル:明細欄テーブルは1:多のリレーションシップがある時、概要テーブルが主キーになると、Viewから呼び出しずらくならないか
②保存した後、編集画面でCore Dataを呼び出すとき、2つのENTITIYの全てのカラムを呼び出すことができるか
1ヶ月間もがいているうちに、1レコード(行)に全てのデータを保存する方法なら明細欄の保存と呼び出しができると思い、このようなやり方になりました。
Core DataはiCloudと連携できる点が魅力と思い、採用しました。
もし私が質問したような1レコード(行)に全てのデータを保存する方法を使わない場合、
データベースを普通のファイルやRealm,Firebase等に変更する方がいいのか、
リレーションシップを使う方法が適しているのか、
アドバイス頂けると幸いです(T T)
よろしくお願い致します。
コメントありがとうございます。
そういう理由だったのですね。
1ヶ月進まないのはちょっと苦痛ですね・・
iCloudとの連携を考えるのでしたら、
Realm、FirebaseなどよりCore Dataの方が良いのかもしれませんね。
リレーションシップを使う方法が良い気がしますが、
具体的な問題点を正しく認識できていないかもしれませんので、
まだなんとも言えないです・・
---
「リレーションシップを使ったCore Dataへの保存と呼び出しをできなかった」
というのは、Fetchで特定のレコードを取得できないということでしょうか?
Filtering Results
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/FetchingObjects.html#//apple_ref/doc/uid/TP40001075-CH6-SW3
Fetch request
https://developer.apple.com/library/archive/documentation/DataManagement/Devpedia-CoreData/fetchRequest.html#//apple_ref/doc/uid/TP40010398-CH26-SW1
ご返信ありがとうございます。
苦痛です・・・
リレーションシップを使う方法で進め、諦めず、形作っていこうと思います。
Fetchで概要テーブルの特定のレコードは取得できますが、リレーションシップを使って明細欄テーブルを呼び出すことができませんでした。
保存の方でも、概要テーブルの保存はできますが、明細欄テーブルに保存することができませんでした(TT)
新規作成するCreateView.swiftで保存ボタンを押し、Core Dataに保存する処理を行う部分において、リレーションシップの使い方が分からないままになっています。
// 保存ボタン押下時の処理
private func createEstimate() {
let outline = OutlineTbl(context: viewContext)
let detail = DetailTbl(context: viewContext) // ←viewContextの2個目を呼び出して概要テーブルと明細テーブルそれぞれに保存できるのか?
outline.Number = Number
outline.prjName = prjName
outline.Date = createDate
outline.updateDate = Date()
detail.productName = productName
// 生成したインスタンスをCoreDataに保存する
try? viewContext.save()
presentation.wrappedValue.dismiss()
}
リンクありがとうございます。
初めて見るリンクで参考になります。今から読みます。
回答1件
あなたの回答
tips
プレビュー

