如何使用 Realm 编写更好的数据访问层

2024-03-03

我一直在一些小项目中使用 Realm,我非常喜欢它。我希望继续在更大的项目中使用它,并且我正在寻找更好的数据访问层结构。

我遇到过这个类似的question https://stackoverflow.com/q/33592572/1077789并尝试以我在那里找到的信息为基础。那里讨论的方法是 DAO 模式,所以我尝试了一下。

这是我的模型课。

class Chat: Object {
    dynamic var id: String = ""
    dynamic var createdAt: Date = Date()
    dynamic var creatorId: String = ""
    dynamic var title: String?
    let chatMessages = List<ChatMessage>()

    override static func primaryKey() -> String? {
        return "id"
    }

    convenience init(fromJSON json: JSON) {
        self.init()
        // ...
    }
}

然后我创建了一个ChatDAOProtocol保存所有方便的辅助方法。

protocol ChatDAOProtocol {
    func addMessage(_ message: ChatMessage)
    func getChatThumbnail() -> UIImage
    func getParticipants(includingMe: Bool) -> [Participant]?
    static func getChat(fromId id: String) -> Chat?
    static func getChat(fromCreatorId id: String) -> Chat?
}

最后我创建了另一个类ChatHelper实现了所有这些协议方法。

class ChatHelper: ChatDAOProtocol {
    func addMessage(_ message: ChatMessage) {

    }

    func getChatThumbnail() -> UIImage {
        return UIImage()
    }

    func getParticipants(includingMe: Bool) -> [Participant]? {
        return nil
    }

    static func getChat(fromId id: String) -> Chat? {
        return nil
    }

    static func getChat(fromCreatorId id: String) -> Chat? {
        return nil
    }

}

这似乎已经比将所有与数据库相关的代码散布在 VC 和其他东西上要好。但我还是有一些疑问。

例如,假设我需要获取聊天的所有参与者,现在我必须调用ChatHelper班级。如果我只想获取聊天标题,我可以调用title的财产Chat对象本身。看起来不是一个非常统一的界面。我是否应该在助手中包含所有属性的 getter 和 setter?所以Chat对象永远不会被直接调用(除了创建一个实例)。

Or

我应该做Chat对象本身符合ChatDAOProtocol协议?因此,所有便捷方法以及属性都可以直接从Chat直接对象?

或者有比这两种更好的方法吗?


我是 Realm 的新手,但我编写此代码是为了以通用方式访问我的对象。我在从后台线程访问此方法时仍然遇到一些问题,但我希望它有所帮助!

import Foundation
import RealmSwift


class GenericDAOImpl <T:Object> : GenericDAO {

  //  MARK: setup

  var realm: Realm?
  init() {
    do {
      realm = try Realm()
    } catch {
      logger.error("Realm Initialization Error: \(error)")
    }
  }

  //   MARK: protocol implementation

  func save(_ object: T) -> Bool {
    guard let `realm` = realm else {
      return false
    }

    do {
      try realm.write {
        realm.add(object)
      }
    } catch {
      return false
    }

    return true
  }

  func saveAll(_ objects: [T]) -> Int {
    var count = 0
    for obj in objects {
      if save(obj) { count += 1 }
    }
    return count
  }

  private func findAllResults() -> Results<T>? {
    return realm?.objects(T.self)
  }

  func findAll() -> [T] {
    guard let res = findAllResults() else { return [] }
    return Array(res)
  }

  func findByPrimaryKey(_ id: Any) -> T? {
    return self.realm?.object(ofType: T.self, forPrimaryKey: id)
  }

  func deleteAll() {
    guard let res = findAllResults() else { return }

    do {
      try realm?.write {
        self.realm?.delete(res)
      }
    } catch {
      logger.error("Realm Error Deleting Objects: \(error)")
      return
    }
  }

}

我忘记展示我的 GenericDAO 协议:

protocol GenericDAO {
  associatedtype T:Object

  func save(_ object: T) -> Bool

  func saveAll(_ objects: [T]) -> Int

  func findAll() -> [T]

  func findByPrimaryKey(_ id: Any) -> T?

  func deleteAll()

}

创建实例:

let movieDAO = GenericDAOImpl<Movie>()

我仍在努力看看这是否是最好的方法,但无论如何它对我帮助很大。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 Realm 编写更好的数据访问层 的相关文章

随机推荐