iOS
Swift
Realm
RealmSwift

SwiftでRealmを使う時のTips(1) アクセサとエンティティ編

More than 1 year has passed since last update.


目次

SwiftでRealmを使う時のTips まえがき

SwiftでRealmを使う時のTips(1) アクセサとエンティティ編

SwiftでRealmを使う時のTips(2) 生成とオートインクリメント編

SwiftでRealmを使う時のTips(3) NSPredicate編


アクセサ(DAO)とエンティティ(DTO)

データを扱うときは DAODTO という設計概念がありますね

厳密に正しいかどうかわかりませんが

ざっくりいうと「データを管理するヤツ」 と 「データそのもの」 は分離させる設計概念です

まぁ、健全なみなさんはちゃんとやってますよね・・・

これがたまにごっちゃにして書いている人がいるので

たまにソースを読んでてこちらもごっちゃになります

Realm自体には、こいつらを分離させるためのクラス体系はありません

なので、最初に自分で分離させておくことは少なくとも大事だと感じました


NBRealmEntity.swift

public class NBRealmEntity: RealmSwift.Object {

public static let IDKey = "id"
public static let CreatedKey = "created"
public static let ModifiedKey = "modified"

public dynamic var id : Int64 = 0 // = NBRealmEntity.IDKey

public dynamic var created = NSDate() // = NBRealmEntity.CreatedKey

public dynamic var modified = NSDate() // = NBRealmEntity.ModifiedKey

public override static func primaryKey() -> String? {
return NBRealmEntity.IDKey
}
}



NBRealmAccessor.swift

import UIKit

import RealmSwift

public class NBRealmAccessor<T: NBRealmEntity> {

public typealias Entity = T

public var realm: Realm { return try! Realm() }

public init() {}
}


実装は上記のとおり2種類のクラスを用意します

ちなみにプレフィックスのNBは自分の屋号からとってきたもので特に意味はありません

(外してもらってもいいです)


エンティティ

データそのものを指すクラスは "エンティティ" という名前にしています

他にも「オブジェクト」や「VO」「データ」「レコード」といった名前で

呼ぶ人もおられると思いますが、

ここではそのように名づけました

IDInt64型にしていますが

よほどのことがない限りはIntでもリソースの枯渇はないと思います

なので Int64型 にこだわる必要はまったくないですが

ここではそのままにしています


アクセサ

データを管理するクラスは "アクセサ" という名前にしています

基底クラスでジェネリクスをとらせてますので

こいつは「あるエンティティ専用のアクセサ」として使うことができます

こんな感じですね


class UserEntity: NBRealmEntity {
// something
}

class UserAccessor: NBRealmAccessor<UserEntity> {
// something
}

UserAccessorUserEntity に関するお仕事しかしないと

これで決めてやったも当然です

責務が狭まったこのクラスは、これであまりソースが散らかることがなくなります (本当かな?)

で、このアクセサは、狭義のモデルクラスになります

オブジェクトの死滅が早いコントローラに、モデルを所持させてはよくないです

ゆえに、呼び出しは下記のように実装すべきですねぇ

// こちらはダメな例

class ViewController: UIViewController {
public override func viewDidLoad() {
super.viewDidLoad()

let userAccessor = UserAccessor()
userAccessor.hoge()
}
}

// こういう感じにしておきたい

class Model {
static let userAccessor = UserAccessor()
}

class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
Model.userAccessor.hoge()
}
}


両者の関係性

ここでエンティティとアクセサの両者を使う時のルールを確認します


  • エンティティは必ずアクセサによって作られる

let user = UserEntity()

みたいなことができるのは唯一アクセサクラスだけというのを徹底します

たとえば、コントローラやビューに書いていては行けませんし、

モデルクラスであっても無関係な処理をしてるクラスでは絶対にインスタンス化をしません

これで 「UserEntity をうんぬんかんぬんしてるってことは・・・、UserAccessor だ!」と

メンテナンスの時に安心できますよね


  • エンティティをデータベースに保存するのは必ずアクセサ

エンティティはただの変数の器。データの固まり

こいつ自身が単独で恒久的データをいじってしまうのはあまりよくないです

なかなか悩ませるのがRealmのオシャレな(?)機能である

リアルタイムアップデートというやつです

オブジェクトの値を変えると、KVOによってそのままデータベースも書き変わるというもの

まぁ便利なんだけど、逆に不便な場面が色々と出てきました

そこは場面によって使い分けも必要かと思いますが、

原則論としては、データベースの書き換えはアクセサ経由でないとやらせない

というルールをしっかりしておけば

CRUDが散らかることが減るかなぁと個人的には思っております