SwiftUIでいこう! - RealmをSPMで使う。仕上げ。
に前回は基本的な部分は大事そうなところを抜き出して書きました。完成に近づけるために参考動画を見ながらもう少し機能をつけていきます。
データの削除、更新の機能をつけます。
その前に、データの追加部分から見てみます。ツールバーの"+"ボタンを押して AddPageView()を呼び出すことから始まります。
.toolbar{
ToolbarItem(placement: .navigationBarTrailing){
Button(action: {
modelData.openNewPage.toggle()
modelData.updateObject = nil
}){
Image(systemName: "plus")
.font(.title2)
}
}
}
.sheet(isPresented: $modelData.openNewPage, content: {
AddPageView()
.environmentObject(modelData)
})
AddPageView()を開いたら、入力部分
List{
Section(header: Text("Title")){
TextField("",text:$modelData.title)
}
Section(header: Text("Detail")){
TextField("",text:$modelData.detail)
}
}
に入力して、ツールバーのボタン"Done"を押すことで記録されます。
.toolbar{
ToolbarItem(placement: .navigationBarTrailing){
Button(action: {modelData.addData(presentation:presentation)},label:{
Text("Done")
})
}
ToolbarItem(placement: .navigationBarLeading){
Button(action: {presentation.wrappedValue.dismiss()},label:{
Text("Cancel")
})
}
}
ここで追加したあと前の画面に戻る機能をつけています。キャンセルの場合も同じで、前の画面に戻るようにしています。
@Environment(\.presentationMode) var presentation
を使っています。@Environment(\.presentationMode)をつけて変数宣言し、
modelData.addData(presentation:presentation ・・・追加
presentation.wrappedValue.dismiss() ・・・キャンセル
とすることで前画面に戻ることができます。
次に削除、更新ですが、HomeViewの
.contextMenu(menuItems:{
Button(action: {modelData.deleteData(object: card)}, label: {
Text("Delete Item")
})
Button(action: {
modelData.updateObject = card
modelData.openNewPage.toggle()
}, label: {Text("Update Item")
})
})
の部分で削除、更新実行します。コンテクストメニューで、画面を長押しすることでボタンが出てきて、選択することで機能します。
削除はmodelData.deleteData(object: card){}部分の実装、DBViewModel()で定義します。
func deleteData(object:Card){
guard let dbRef = try? Realm() else {return }
try? dbRef.write{
dbRef.delete(object)
fetchData()
}
}
realmでの削除の命令"try? dbRef.write{}!を組み込み、fetchData()で削除されたものをcompactMapで除き変数cardsに代入します。
func fetchData(){
guard let dbRef = try? Realm() else {return }
let results = dbRef.objects(Card.self)
self.cards = results.compactMap{$0}
@Published var cards:[Card] = []
でデータは即座に反映されます。
次に更新ですが、DBViewModelで管理します。まず変数宣言です。
@Published var updateObject:Card?
この変数を使ってデータを取得して処理を行います。データの取得ですが、リストの項目を長押しすることで更新できます。そのコードはHomeViewにあり、
.contextMenu(menuItems:{
Button(action: {modelData.deleteData(object: card)}, label: {
Text("Delete Item")
})
Button(action: {
modelData.updateObject = card
modelData.openNewPage.toggle()
}, label: {
Text("Update Item")
})
})
Button(action: {
modelData.updateObject = card
modelData.openNewPage.toggle()
}, label: {
Text("Update Item")
})
の部分にあたります。この取得したデータを表示部分のAddPageView()、データ部分のDBViewMode()に渡して処理します。
表示部分はAddPageView()の
NavigationView{
}
.onAppear(perform: modelData.setUoInitialData)
.onDisappear(perform: modelData.deinitData)
}
.onAppear(perform: modelData.setUoInitialData)
でsetUoInitialData()の処理を行います。実装部分は以下
func setUoInitialData(){
guard let updateData = updateObject else {return}
title = updateData.title
detail = updateData.detail
}
これを持って、DBViewMode()にデータを渡します。
func addData(presentation:Binding<PresentationMode>){
let card = Card()
card.title = title
card.detail = detail
guard let dbRef = try? Realm() else {return }
try? dbRef.write{
guard let avaiableObject = updateObject else{
dbRef.add(card)
return
}
avaiableObject.title = title
avaiableObject.detail = detail
}
fetchData()
presentation.wrappedValue.dismiss()
}
guard let avaiableObject = updateObject else{
dbRef.add(card)
return
}
updateObjectにデータがなければ、通常の
dbRef.add(card)
データが更新され、updateObjectにデータがあれば、
avaiableObject.title = title
avaiableObject.detail = detail
で今あるデータの上書きするということです。
これでデータの流れはできました。あとは、AddPageView()が表示された時のタイトルが最初のままだと、"Add Data"なので更新の時は、"Update"としてやるために以下とします。
.navigationTitle(modelData.updateObject == nil ? "Add Data": "Update")
これで実行すると1度更新するとupdateObjectにはデータが入ってしまうので、ずっと更新状態となる問題が出ます。その対処法として、HomeViewの"+"ボタンを押すタイミングで、
Button(action: {
modelData.openNewPage.toggle()
modelData.updateObject = nil
}){
Image(systemName: "plus")
.font(.title2)
}
modelData.updateObject = nil
としてやれば新規ボタンの時にAddPageView()が開く時はまっさらのシートが出てくるようになります。
この記事が気に入ったらサポートをしてみませんか?