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