Sponsor Link
目次
環境
Xcode11.4, MacOS10.15を使います。
Swift5を使って、最新の記述方法で作っていきます。
プロジェクト作成
macOSのAppを選んで、
Swift/SwiftUI/CoreDataを選んで、
プロジェクト作成は、終わり。
CoreData関連のファイルは、後で、Xcodeからコード生成することにもなるので、別グループを作って管理します。
プロジェクト設定の確認
生成されているAppDelegate.swiftのコードを確認すると、以下のようなコードがあります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
func applicationDidFinishLaunching(_ aNotification: Notification) { // Create the SwiftUI view and set the context as the value for the managedObjectContext environment keyPath. // Add `@Environment(\.managedObjectContext)` in the views that will need the context. let contentView = ContentView().environment(\.managedObjectContext, persistentContainer.viewContext) // Create the window and set the content view. window = NSWindow( contentRect: NSRect(x: 0, y: 0, width: 480, height: 300), styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], backing: .buffered, defer: false) window.center() window.setFrameAutosaveName("Main Window") window.contentView = NSHostingView(rootView: contentView) window.makeKeyAndOrderFront(nil) } |
サンプル用の要素作成
作成したアトリビュートに、特に意味はないですが、以下のような要素を作ります。
SwiftUI向け設定
ManagedObjectContextへのアクセスやFetchを用意しておきます。
1 2 3 4 |
@Environment(\.managedObjectContext) var moc @FetchRequest(entity: AppEntity.entity(), sortDescriptors: [] ) var entities: FetchedResults<AppEntity> |
1 2 3 |
lazy var persistentContainer: NSPersistentContainer = { |
CoreDataアトリビュートWrapper作成
CoreDataエンティティにアクセスしやすいように、Wrapperを作っておきます。String等のAttributeは、Attributeの設定で非Optionalにしても、変数としては、String?等のOptional型になってしまうため、常にUnwrapする必要が発生してしまい、記述が煩雑になってしまいます。特にSwiftUIとは相性が良くないと思いますので、このようなwrapperを作っておくと便利です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
extension AppEntity { var strAttr:String { get { return stringAttr ?? "" } set(newValue) { stringAttr = newValue } } var id: String { get { let uuid = uuidAttr ?? UUID() uuidAttr = uuid return uuid.uuidString } } } |
簡単なUIの作成
CoreData操作のためのUIを作っていきます。
まずは、CoreData内に存在する要素を表示するリスト
1 2 3 4 5 6 7 8 9 |
VStack { Text("num of AppEntity \(entities.count)") List(entities, id:\.self) { entity in Text("UUID: \(entity.id) String: \(entity.strAttr) Int64: \(entity.int64Attr)") } } |
作成/削除するためのボタン(とそこから呼ばれる関数)
1 2 3 4 5 6 7 8 9 10 |
VStack { Button(action: {self.createNewEntity()}, label: {Text("Create a new Entity")} ) Button(action: {self.deleteEntities()}, label: {Text("Delete selected Entities")} ) } |
1 2 3 4 5 6 7 8 |
func createNewEntity() { // Entity作成 } func deleteEntities() { // Entity 削除 } |
ここまでのコードをまとめると以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
struct ContentView: View { @Environment(\.managedObjectContext) var moc @FetchRequest(entity: AppEntity.entity(), sortDescriptors: [] ) var entities: FetchedResults<AppEntity> @State private var selections = Set<AppEntity>() var body: some View { HStack { VStack { Text("num of AppEntity \(entities.count)") List(entities, id: \.self, selection: $selections) { entity in Text("id: \(entity.id) int64: \(entity.int64Attr) string: \(entity.strAttr) ") } } VStack { Button(action: {self.createNewEntity()}, label: {Text("Create a new Entity")} ) Button(action: {self.deleteEntities()}, label: {Text("Delete selected Entities")} ) } } } func createNewEntity() { // Entity作成 } func deleteEntities() { // Entity削除 } } |
この段階で機能は動きませんが、実行するとウィンドウが表示されます。
CoreDataでのEntity生成
以前は、insertNewObject等を使っていましたが、いまでは非常に簡単にEntityを作成できます。
1 2 3 |
let newEntity = AppEntity(context: moc) |
CoreDataは、複数のContextを並行して操作することができるので、どのContextに追加するかを指定する必要がありますが、それだけでOKです。
作成した後は、Attributeを設定しておけばokです。
先の // Entity作成 の箇所のコードは以下のようになります。
1 2 3 4 5 6 7 8 |
func createNewEntity() { let newEntity = AppEntity(context: moc) newEntity.uuidAttr = UUID() newEntity.stringAttr = Date().description newEntity.int64Attr = Int64.random(in: 0...256) } |
CoreDataでのEntity削除
Entityを削除するためのコードは、以下です。
1 2 3 |
moc.delete(entity) |
選択されたEntityがselectionsに保持されていますので、それを削除して、終わりです。
1 2 3 4 5 6 7 8 |
func deleteEntities() { for entity in selections { moc.delete(entity) } selections = [] } |
CoreDataでの要素の作成削除
ここまでのコードをまとめると、以下になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
struct ContentView: View { @Environment(\.managedObjectContext) var moc @FetchRequest(entity: AppEntity.entity(), sortDescriptors: [] ) var entities: FetchedResults<AppEntity> @State private var selections = Set<AppEntity>() var body: some View { HStack { VStack { Text("num of AppEntity \(entities.count)") List(entities, id: \.self, selection: $selections) { entity in Text("id: \(entity.id) int64: \(entity.int64Attr) string: \(entity.strAttr) ") } } VStack { Button(action: {self.createNewEntity()}, label: {Text("Create a new Entity")} ) Button(action: {self.deleteEntities()}, label: {Text("Delete selected Entities")} ) } } } func createNewEntity() { let newEntity = AppEntity(context: moc) newEntity.uuidAttr = UUID() newEntity.stringAttr = Date().description newEntity.int64Attr = Int64.random(in: 0...256) } func deleteEntities() { for entity in selections { moc.delete(entity) } selections = [] } } |
実行すると以下のようになります。
“Create a new Entity”ボタンを押すと、新しいEntityが生成されます。
“Delete selected Entities”を押すと、選択されている要素が削除されます。
CoreData とアーキテクチャ
CoreData をお試して使う分には、Xcode が生成してくれるコードを使って試してみるのが良いと思います。
少し凝った機能を実装しようとすると、適切なアーキテクチャを選択しておくことが重要となります。
MVVM での実装例を説明していますので、以下の記事も参考にしてください。















Sponsor Link