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

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

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

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

Core Data

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

Swift

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

1回答

1603閲覧

Core DataでBinary Dataを使用している場合に、previewを表示したい

key0

総合スコア0

canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

Core Data

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

Swift

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

0クリップ

投稿2021/07/22 02:30

編集2021/07/25 12:00

前提・実現したいこと

Core DataでBinary Dataを用いた状況で
Canvasのpreviewを表示したい

Binary Dataを使わなければ表示できるが、使うとエラーになる。

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

"Persistent store migration failed, missing mapping model." →再起動や触れているうちに上記は出なくなり、以下が出るようになりました。 "Fatal error: Unexpectedly found nil while unwrapping an Optional value"

該当のソースコード

Swift5.4 ios14.5 Xcode12.5
Core Dataで以下のEntityを作成 ItemEntity name:String detailArray:Binary Data

detailArrayには独自クラス:Detailの配列を格納したい。Detailクラスは次の通り。

import Foundation public class Detail:NSObject,NSCoding { var date: Date var state: Int = 0 // 1,2,3,4 // イニシャライザ init(date:Date,state:Int){ self.date = date self.state = state } // NSCording型で必要なもの public func encode(with coder: NSCoder) { coder.encode(self.date, forKey: "date") coder.encode(self.state, forKey: "state") } // NSCording型で必要なもの public required init?(coder: NSCoder) { self.date = coder.decodeObject(forKey: "date") as! Date self.state = coder.decodeObject(forKey: "state") as! Int } }

Persistence.swiftで初期値を入れておかないとPreviewでエラーになるため以下を設定

struct PersistenceController { static let shared = PersistenceController() static var preview: PersistenceController = { AttributeSecureTransformer.register() let result = PersistenceController(inMemory: true) let viewContext = result.container.viewContext do { let newItem = ItemEntity(context: viewContext) newItem.name = "アイテムネーム1" // 問題と予測している箇所--ここから let detail1:Detail = Detail(date: Date(), state: 2) let entity2:Detail = Detail(date: Date(), state: 4) let resultsData: Data = try NSKeyedArchiver.archivedData( withRootObject:[detail1, detail2], requiringSecureCoding: false) as Data newItem.detailArray = resultsData // 問題と予測している箇所--ここまで } catch let error { print(error.localizedDescription) } do { try viewContext.save() } catch { 省略 } return result }() let container: NSPersistentContainer init(inMemory: Bool = false) { 省略 }

[追記]
表示は以下DetailViewで実施。
前提
親画面NameListViewにItemEntity.nameを表示し、タップしたら
子画面DetailViewにItemEntity.detailArrayのリストを表示したい。

import SwiftUI import CoreData struct DetailView: View { @ObservedObject var oneItemEntity:ItemEntity func getDetailList() -> [Detail] { var detailArray: [Detail] = [] do { detailArray = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(oneItemEntity.detailArray!) as! [Detail] } catch let error { // **** ここでエラー Unexpectedly found nil while unwrapping an Optional value**** print(error.localizedDescription) } return detailArray } var body: some View { VStack(alignment: .leading) { HStack { Group{ Text("state:") Text("(getDetailList()[0].state)") .font(.title) } } Group{ Spacer() } } } } struct DetailView_Previews: PreviewProvider { static var context = PersistenceController.preview.container.viewContext static var previews: some View { let itemEntity = ItemEntity.init(context: context) return Group { DetailView( oneItemEntity: itemEntity ) } .previewLayout(.fixed(width: 800, height: 70)) } }

参考:親画面NameListView

import SwiftUI struct NameListView: View { @Environment(.managedObjectContext) private var context @FetchRequest( entity: ItemEntity.entity(), sortDescriptors: [ NSSortDescriptor( keyPath: \ItemEntity.name, ascending: true ) ], predicate: nil ) private var items: FetchedResults<ItemEntity> var body: some View { 省略 Core Data のItemEntityについて、detailArrayを定義する前は nameの表示は可能でした。 } } struct NameListView_Previews: PreviewProvider { static var previews: some View { NameListView() .environment( .managedObjectContext, PersistenceController.preview.container.viewContext) } }

試したこと

・ItemEntityを使用しない画面でpreviewを試した際、
上記のままではエラー発生。「問題と予測している箇所」をコメントアウトすればpreviewできる
[追記]
上記は勘違いでした。
ItemEntityを使用しない画面は、preview可能です。
・Transformableというので最初実現しようとしたが断念

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

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

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

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

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

hoshi-takanori

2021/07/22 03:25

preview はどうやって表示していますか?
hoshi-takanori

2021/07/22 22:59

NSKeyedUnarchiver.unarchiveTopLevelObjectWithData に失敗してますね。 原因は self.state = coder.decodeObject(forKey: "state") as! Int で、state は Int なので encode には https://developer.apple.com/documentation/foundation/nscoder/1411568-encode ではなく、 https://developer.apple.com/documentation/foundation/nscoder/1411551-encode が使われるため、decode には https://developer.apple.com/documentation/foundation/nscoder/1409246-decodeinteger を使うのが良いと思います。 また、全体的にエラーチェックが甘いと言うか…。
key0

2021/07/23 01:38

encode,decodeについて情報ありがとうございます。以下直してみました。 誤:self.state = coder.decodeObject(forKey: "state") as! Int 正:self.state = coder.decodeInteger(forKey: "state") 上記修正しましたが、同じ箇所で同じエラーログ出力となりました。 NSKeyedUnarchiverのunarchiveTopLevelObjectWithDataではないメソッドでunarchiveするのかな? とか推測中かつ調査中です。。。 >エラーチェックが甘い 指摘ありがとうございます。おっしゃる通りです。
hoshi-takanori

2021/07/23 03:38 編集

たぶん DetailView_Previews でエラーになってると思いますが、空の itemEntity を生成して、プロパティを何も設定してないせいですね。
key0

2021/07/25 11:48

プロパティを設定することでエラーがなくなり、プレビューが表示できるようになりました。 ありがとうございました。 詳細は別途追記します。
guest

回答1

0

自己解決

以下のようにして解決しました。

###以下と認識していた。
・Core Dataを使う場合、以下の3つである認識だった。
1:初期値の設定はPersistence.swiftのみ
2:〜_Previews:PreviewProvider{}ではCore Dataの初期値は設定しない→これが誤り。
3:(補足)
viewの@Environment(.managedObjectContext) private var viewContextに対し、
preview時に設定する場合は、
PersistenceController.preview.container.viewContextをpreviewで設定
キーワード:environment,managedObjectContext
今回は説明省略

###・上記2に対する方法
・viewContext自体を渡さない場合は、init後、初期化して渡す必要がある

struct DetailView_Previews: PreviewProvider { static var context = PersistenceController.preview.container.viewContext static var previews: some View { let itemEntity = ItemEntity.init(context: context) // 上記ではPersistence.swiftで設定した値が入っているわけではないらしい // 以下を追加--ここから itemEntity.name = "アイテムネーム2" let detail1:Detail = Detail(date: Date(), state: 2) let entity2:Detail = Detail(date: Date(), state: 4) let resultsData: Data = try NSKeyedArchiver.archivedData( withRootObject:[detail1, detail2], requiringSecureCoding: false) as Data do{ let resultsData: Data = try NSKeyedArchiver.archivedData(withRootObject:[entity1, entity2], requiringSecureCoding: false) as Data itemEntity.detailArray = resultsData } catch let error { print(error.localizedDescription) } // 以下を追加--ここまで return Group { DetailView( oneItemEntity: itemEntity ) } .previewLayout(.fixed(width: 800, height: 70)) } }

投稿2021/07/25 12:01

key0

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問