I tried using Realm with Swift UI

Introduction

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. ezgif.com-video-to-gif.gif

environment

Swift 5.3 Xcode 12.0.1 Cocoapods 1.9.3 RealmSwift 5.4.7

Background

Recently, I first encountered Realm in Swift and was wondering how it could be implemented in Swift UI, so I started looking into it.

Implemented behavior

・ 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

Source code

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

Referenced site

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.

in conclusion

Thank you for reading to the end. I hope it helps people who use SwiftUI and Realm.

Recommended Posts

I tried using Realm with Swift UI
I tried using JOOQ with Gradle
I tried using Scalar DL with Docker
I tried using OnlineConverter with SpringBoot + JODConverter
I tried using OpenCV with Java + Tomcat
I tried using Gson
I tried using TestNG
I tried using Galasa
Starting with Swift Swift UI
[Android] I quit SQLite and tried using Realm
I made blackjack with Ruby (I tried using minitest)
I tried DI with Ruby
Progress made with Swift UI
I tried using azure cloud-init
I tried using Apache Wicket
I tried using Java REPL
I tried UPSERT with PostgreSQL.
I tried BIND with Docker
[Swift] I tried to implement Instagram profile-like UI with UICollectionView only with code without storyboard
I tried to introduce UI animation to Pokedex using Poké API
I tried to get started with Swagger using Spring Boot
I tried using the CameraX library with Android Java Fragment
I tried using anakia + Jing now
I tried using Spring + Mybatis + DbUnit
I tried morphological analysis with MeCab
I tried to interact with Java
I tried UDP communication with Java
I tried using Java8 Stream API
I tried using JWT in Java
I tried GraphQL with Spring Boot
[Android] I tried using Coordinator Layout.
I tried Flyway with Spring Boot
I tried using Pari gp container
I tried using WebAssembly Stadio (2018/4/17 version)
I tried customizing slim with Scaffold
I tried using Java memo LocalDate
I tried using GoogleHttpClient of Java
I tried connecting to MySQL using JDBC Template with Spring MVC
[Swift] I tried using ColorPicker (the one that can easily select colors) added in iOS14 [Swift UI]
I tried using Elasticsearch API in Java
Customize View with View Modifier in Swift UI
I tried using Java's diagnostic tool Arthas
I tried using UICollectionViewListCell added from Xcode12.
I tried to get started with WebAssembly
Shiritori map app made with Swift UI
I tried time-saving management learning with Studyplus.
It's new, but I tried using Groonga
I tried playing with BottomNavigationView a little ①
I tried Lazy Initialization with Spring Boot 2.2.0
I tried to implement ModanShogi with Kinx
I created and set my own Dialect with Thymeleaf and tried using it
[iOS] I tried to make a processing application like Instagram with Swift
Swift UI 100 knocks
I tried using Docker for the first time
[For beginners] I tried using DBUnit in Eclipse
I tried barcode scanning using Rails + React + QuaggaJS
I tried to verify AdoptOpenJDK 11 (11.0.2) with Docker image
I tried to manage struts configuration with Coggle
[For beginners] I tried using JUnit 5 in Eclipse
I tried to manage login information with JMX
I tried writing CRUD with Rails + Vue + devise_token_auth