I created a sample app using Realm in Swift UI. It took me a while to understand, so I'm writing it as my own output. ↓ It is an application that works like this. The numbers on the right are randomly obtained from 0 to 100.
Swift 5.3 Xcode 12.0.1 Cocoapods 1.9.3 RealmSwift 5.4.7
Recently, I first encountered Realm in Swift and was wondering how it could be implemented in Swift UI, so I started looking into it.
・ Add button Added "First Title" and a row of random numbers from 0 to 100 to the List ・ Trash can mark Delete the corresponding line ・ Delete all button Delete all lines ・ Press and hold the line title Renamed "First Title" to "Changed Title" and reacquired random numbers ・ Save as Realm Save data even if you drop the app
First, write the code that is the source of the data.
ItemDB.swift
import RealmSwift
//Class for Realm
class ItemDB: Object {
@objc dynamic var id = 0
@objc dynamic var title = ""
@objc dynamic var number = 0
//Using the primary key is convenient for updating and deleting data
override static func primaryKey() -> String? {
"id"
}
}
Item.swift
import Foundation
struct Item: Identifiable {
let id: Int
let title: String
let number: Int
}
extension Item {
init(itemDB: ItemDB) {
id = itemDB.id
title = itemDB.title
number = itemDB.number
}
}
ItemStore.swift
import RealmSwift
final class ItemStore: ObservableObject {
private var itemResults: Results<ItemDB>
//Set DB data in itemResults
init(realm: Realm) {
itemResults = realm.objects(ItemDB.self)
}
var items: [Item] {
itemResults.map(Item.init)
}
}
In ItemStore.swift, also describe the following methods that operate the DB. It is for performing the above implemented operation.
--create (add data) --update --delete (delete data) --deleteAll (delete all data)
ItemStore.swift
extension ItemStore {
//Add data
func create() {
//If you do not write this, you will not be able to tell View of DB changes.
objectWillChange.send()
do {
let realm = try Realm()
let itemDB = ItemDB()
itemDB.id = UUID().hashValue
itemDB.title = "First Title"
itemDB.number = Int.random(in: 0...100)
try realm.write {
realm.add(itemDB)
}
} catch let error {
print(error.localizedDescription)
}
}
//Update data
func update(itemID: Int) {
objectWillChange.send()
do {
let realm = try Realm()
try realm.write {
realm.create(ItemDB.self,
value: ["id": itemID, "title": "Changed Title", "number": Int.random(in: 0...100)],
update: .modified)
}
} catch let error {
print(error.localizedDescription)
}
}
//Delete data
func delete(itemID: Int) {
objectWillChange.send()
guard let itemDB = itemResults.first(where: { $0.id == itemID})
else {
return
}
do {
let realm = try Realm()
try realm.write {
realm.delete(itemDB)
}
} catch let error {
print(error.localizedDescription)
}
}
//Delete all data
func deleteAll() {
objectWillChange.send()
do {
let realm = try Realm()
try realm.write {
realm.deleteAll()
}
} catch let error {
print(error.localizedDescription)
}
}
}
Next, I will write the code that will be View.
ItemRowView.swift
import SwiftUI
struct ItemRowView: View {
@EnvironmentObject var store: ItemStore
let item: Item
var body: some View {
HStack{
Text(item.title)
//Press and hold the title to update the data
.onLongPressGesture {
store.update(itemID: item.id)
}
Spacer()
Text(String(item.number))
//Install trash can mark and implement deletion
Image(systemName: "trash.circle.fill")
.resizable()
.frame(width: 24, height: 24)
.foregroundColor(.red)
.onTapGesture {
store.delete(itemID: item.id)
}
}
}
}
ItemListView.swift
import SwiftUI
struct ItemListView: View {
@EnvironmentObject var store: ItemStore
let items: [Item]
var body: some View {
List {
Section(header: sectionHeaderView) {
ForEach(items) { item in
HStack{
ItemRowView(item: item)
}
}
}
}
.navigationTitle("RealmDB list")
}
//Add button and delete button in header
var sectionHeaderView: some View {
HStack {
Button("add to", action: store.create)
Spacer()
Button("Delete all", action: store.deleteAll)
}
}
}
ContentView.swift
import SwiftUI
struct ContentView: View {
@EnvironmentObject var store: ItemStore
var body: some View {
NavigationView {
ItemListView(items: store.items)
}
}
}
Finally, rewrite a part of "SceneDelegate.swift" and it's done.
SceneDelegate.swift
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let windowScene = scene as? UIWindowScene {
do {
let realm = try Realm()
let window = UIWindow(windowScene: windowScene)
//Where to load Realm first
let contentView = ContentView()
.environmentObject(ItemStore(realm: realm))
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
} catch let error {
fatalError("Failed to open Realm. Error: \(error.localizedDescription)")
}
}
}
** Click here for the entire source code ** https://github.com/takuma-2531/SwiftUI_Realm_1To1
https://www.raywenderlich.com/12235561-realm-with-swiftui-tutorial-getting-started This site was the easiest to understand when I investigated how to use Realm in SwiftUI. Although it is in English, I read it using Google Translate. The above sample is a simpler version of the code on this site.
Thank you for reading to the end. I hope it helps people who use SwiftUI and Realm.
Recommended Posts