【Swift/Realm】Results構造体とは?遅延ロードとキャスト方法

この記事からわかること

  • Realm Swiftデータ取得する方法
  • Results<Element>構造体の使い方
  • RealmSwift.Listクラスとの違い
  • 仕組み遅延ロードとは?
  • Array型やRealmSwift.Listへのキャスト方法

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

Realm Swiftでデータベースからデータを取得した際のデータ型であるResults構造体についてまとめていきます。

参考文献: Results構造体

RealmのResults構造体とは

@frozen
public struct Results<Element> : Equatable, RealmCollectionImpl where Element : RealmCollectionValue
extension Results: RealmSubscribable
extension Results: Encodable where Element: Encodable

Results構造体はRealm Swiftに定義されているデータベース内から取得したオブジェクトのクエリ結果を表す型です。クエリとはデータベースからデータを抽出する命令であり、その結果(result)をコレクション形式で保持しています。

let realm = try! Realm()
                
let travelTable = realm.objects(Travel.self) // Travelが定義してあるとして
print(travelTable)
print("----------")
print(type(of: travelTable))


Results<Travel> <0x140a06570> (
	[0] Travel {
		id = 6458cf17be73f8895a46429f;
		name = 鹿児島旅行;
		Date = 2023-05-08 10:29:43 +0000;
	},
	[1] Travel {
		id = 6458cfce532e5dede7667aee;
		name = 沖縄旅行;
		Date = 2023-05-08 10:32:46 +0000;
	}
)
----------
Results<Travel>

コレクション形式で保持しているため、要素番号(インデックス)を指定[1]することで中の要素にアクセスできます。

print(travelTable[1])
print("----------")
print(type(of: travelTable[1]))

Travel {
	id = 6458cfce532e5dede7667aee;
	name = 沖縄旅行;
	Date = 2023-05-08 10:32:46 +0000;
}
----------
Travel

objectfilterwhereなどデータベースからデータを抽出やフィルタリングする役割を持つメソッドの返り値がResults<Element>になっています。

let okinawaTravelTable = realm.objects(Travel.self).filter("name = '沖縄旅行'")

またResults構造体は直接インスタンス化することはできず、クエリ結果としてのみインスタンス化されることが期待されているようです。

let travel = Travel()
travel.name = "東京旅行"
Results<Travel>(travel as! RLMCollection)
// Error:'Results<Element>' initializer is inaccessible due to 'internal' protection level
// 「内部」保護レベルのため、「Results<Element>」のイニシャライザにアクセスできません

Listクラスとの違い

Realm Swiftには別のコレクション形式としてListクラスが定義されています。こちらはSwiftのArrayと同じような振る舞いをするクラスになっています。Results構造体は自身で使用することはなく、あくまで結果としてのデータ型であり、Listクラスはテーブル定義や変数の型などにも使用できるデータ型になります。


@State  var list:RealmSwift.List<Travel> = RealmSwift.List<Travel>()
Button {
    // レコードの生成
    let travel = Travel()
    travel.name = "沖縄旅行"
    list.append(travel)
    
    print(list)
} label: {
    Text("Add List")
}

このListクラスと同じAPIを使用してResults構造体では要素数の取得やフィルタリングといった機能が利用でき、またメソッドチェーンを使用することで複数の条件を指定することができます。

travelTable.count
travelTable.first!

取得するのはコピーではなく実際のデータ

クエリ結果として取得したResultsインスタンスはデータのコピーではなく実際のデータと繋がっています。なのでResultsインスタンスへの更新はそのままデータベースの更新になります。

let travelTable = realm.objects(Travel.self).filter("name = '沖縄旅行'")
try! realm.write{
    travelTable.first?.name = "Okinawa Travel"
}

遅延ロード:Lazy Loading

データベースには膨大なデータが蓄積されますが、Realmでは読み込みを遅延(遅延ロード:Lazy Loading)させることで高速化を実現しています。一度に大量のデータを読み込む仕組みに比べて、必要なデータを必要な時にだけ読み込む仕組みにすることでアプリのパフォーマンスを向上させているようです。

これはクエリによるフィルタリングをかけている時にも機能するようで「条件に一致する最初の10個のオブジェクトを取り出す」といったクエリが実行される際には10個以上一致するものがあっても最初の10個の要素のみにアクセスします。

配列へのキャスト

ResultsインスタンスはArrayのイニシャライザを使用することで簡単にキャストすることができます。

// Resultsを配列に変換する
let travelTable = realm.objects(Travel.self)
let array:Array<Travel> = Array(travelTable)
print(type(of: array)) // Array<Travel>

RealmSwift.Listへのキャスト

ResultsインスタンスはRealmSwift.Listappend(objectsIn:)メソッドを使用することでキャストすることができます。Array型でもRealmSwift.Listに変換可能です。

let travelTable = realm.objects(Travel.self) // Results型
list.append(objectsIn: travelTable)   // RealmSwift.List型

or 

let travelTable = realm.objects(Travel.self)    // Results型
let array:Array<Travel> = Array(travelTable)    // Array型
list.append(objectsIn: array)                   // RealmSwift.List型

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index