[Swift][Architecture] ValueType Model is useful?

     
⌛️ 5 min.

In this post, I’ll try to explain when/why we should use ValueType Model.

Environment

  • macOS Monterey 12.1
  • Xcode 13.2.1
  • iOS 15.2

Note: I used term “DB” like CoreData or Realm, so it is a little bit different from general definition…

ValueType Model

After some trial/implementation, I found we can NOT use ValueType Model everywhere. so I’ll try to find where we should use, where we should NOT.

Assume “standard” value type model in the following.

Benefit from ValueType Model

Similar benefit from using value type.

Apple documentaion is here.

In the following post, I explained using ValueType model makes easy to implement UNDO/REDO functionality.
[Swift]Value-type なモデルを使った UNDO の実装(その2: Value-type で モデルを作成)

Loss from using ValueType Model

ofcourse some loss also comes from using ValueType model.

With using ValueType Model, followings are major losses.

  • need to have all data on memory
MEMO

With using ValueType Model, when you want to change the data, you need to ask for changes to model. Because usually you will receive copy of the data, so you need to ask for changes to Model.
This is not only Loss but also Benefit from using ValueType.

To think of above points, let’s recap what “DB” does for us.

DB

DB gives us many functionalities, one of the functionalities is “data handling without loading data on memory”.

It means we can have only necessary data on memory. Some data may be NOT loaded at launch. In DB, “unloaded state” is called “fault state”.

of course when it is judged as “necessary”, DB will load it automatically.

Fault state management

So, DB takes care of “fault state”.

Apple documentation is here.

Fault state management is necessary

If there are many many data in DB, it is NOT practical to load all of the data on memory.

We need to load data piece by piece along its necessity.
Then at some point, we need to unload the data from memory to use the memory for other data.
For example, if view disappears, some data might become unnecessary so unload from memory to load other data for new views.

This “Fault state management” can become complicated system, because data element may have some relations to other elements. It means if one data element looks unnecessary, but another data might refer to the element. so it is not easy to judge whether this data element is still necessary.

Usually these kind of manamgenet uses Graph. This is the reason CoreData is using Object Graph management.

Fault state in ValueType Model

Let’s consider introducing Fault state management in ValueType model.

We can use optional for ValueType model. Using optional looks good idea, I believe.


struct Element: Identifiable {
  var id: UUID
  var elementData: Data?
}

assume ID is used for access. Probably I’ll implement fault management like “when need to access element, check elementData. If elementData is .none, data will be loaded. if it become unnecessary, set nil to data”.

But there are another difficulties. “read will be loaded” is the point.

It means we need to load “partial” data from disk. But how?

Read whole data file to read part of the data? Read whole data file every time when we need to read additional data? It looks not practical approach.

It means we need to have “partial data readability”. (I don’t know official terms, hope you can get the feeling.)

so if we want to use ValueType Model for large amount of data, we need to have persistent layer which has such feature.

i.e. we need to have persisitent layer which has “partial data readability” to use ValueType model for large amount data.

Persistent layer

I can imagine some reasons why we use CoreData/Realm. one of the reason is “Object Graph Management” I mentioned above.
but is there any other reason?

let’s start from simple persistent layer: JSON file.

JSON file v.s. CoreData/Realm

Let’s consider using JSON file as persistent layer ( actually persistent layer is file system, JSON is just file format. but it is not the point.)

With using “Codable”, we can save/load data into/from JSON file easily.

“Partial data readability” of Persistent Layer

With using DB, we can do followings

  • load specific part of data: OK
  • update specific part of data: OK
  • remove specific part of data: OK

Let’s consider characteristics of JSON file from above view points.

From JSON point of view,

  • load specific part of data: NG, need to load whole file
  • update specific part of data: NG, need to write whole file
  • remove specific part of data: NG, need to write whole file

It means even if we can manage fault state with ValueType model, there are still some issues.
At least JSON file is not enough. Probably other file formats on file system would be not enough.
Actually above difficulties comes from File system, not from JSON file format itself.

use ValueType Model with Persistent Layer

From above observation, I found I need to use ValueType Model together with “nice” Persistent Layer.

But is there any such kind of nice Persistent Layer?

We want to have the Persistent Layer which has “partial data readability, but nothing more”.

After some research, many DB has fault management and “partial data readability” (of course). But there are no “partial data readability” persistent layer without DB functionalities.

Probably “partial data readability” is essential feature for DB because it is key feature for “fault management”.

Note: I know I’m writing really obvious things. But before writing this post, I was in confusion.

intermediate Summary

It is difficult to use ValueType model without using persistent layer which has “partial data readability” feature for large amount data.

It means we can NOT use ValueType model for large amount data.

In other words, using ValueType Model for small amount data is the ideal use cases for ValueType Model.

In the case, we can load all of the data on memory, no need to load/save partially.

Even for small amount data model, benefit from using ValueType Model is still beneficial.

After this summary, I tried to measure how much memory is used to keep the data.

So we can judge which model (ValueType, ReferenceType) would be good choice.

measurement result

I measured used memory for having the data.

environment, model

environment

macMini2018(intel) + 16G memory + macOS Monterey 12.1 + Xcode 13.2.1
measurement method:”Debug Navigator” – Memory Report on Xcode
Note: value from “High” not from “Memoy Use”

MemoryMeasurement

Model1

Model element has UUID and Int.


struct Element: Identifiable {
  var id: UUID = UUID()
  var intValue: Int = Int.random(in: 0..<1_000_000)
}

Model2

Model element has UUID, Int, String.


struct Element: Identifiable {
  var id: UUID = UUID()
  var intValue: Int = Int.random(in: 0..<1_000_000)
  var doubleValue: Double = Double.random(in: 0..<1_000_000.0)
}

codes for measurement


//
//  ViewModel.swift
//
//  Created by : Tomoaki Yagishita on 2021/12/15
//  © 2021  SmallDeskSoftware
//

import Foundation
import SwiftUI

@main
struct StructDBPerformanceApp: App {
    @StateObject var viewModel = ViewModel()
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
struct Element: Identifiable {
    var id: UUID = UUID()
    var intValue: Int = Int.random(in: 0..<1_000_000)
    var stringValue: String = ["Hello", "Hallo", "こんにちわ"].randomElement()!
}

class ViewModel: ObservableObject {
    let elementDB: [Element]
    public init() {
        // 10_000_000 will vary
        self.elementDB = Array(repeating: Element.init(), count: 10_000_000) 
    }
}

result

used 1 million, 5 million, 10 million, 50 million for each models.

1,000,000 5,000,000 10,000,000 50,000,000
Int 47.8MB 139.3MB 253.6MB 1.14GB
Int+String 62.6MB 214.7MB 405.3MB 1.89GB

Summary:When should we use ValueType Model?

We can use ValueType Model for small amount data application.

When should we use ValueType Model?
  • we can get benefits from ValueType Model for small amount data application
    • Simple Element: up to 10 million elements
    • Somplex Element: up to 1 million elements

Note: it is really depends on your use cases.

Please feel free to contact me.

Leave a Reply

Your email address will not be published. Required fields are marked *