Swift 其中';调用与我的数据库交互的方法的最佳位置是哪里?

Swift 其中';调用与我的数据库交互的方法的最佳位置是哪里?,swift,firebase,model-view-controller,design-patterns,architecture,Swift,Firebase,Model View Controller,Design Patterns,Architecture,我正在创建一个与Firestore数据库交互的应用程序。到目前为止,我有一个单例类,DatabaseManager,它拥有与Firestore数据库相关的所有方法(即get/post方法) 我有一个名为User的用户模型,它的属性包括name、email、photoURL,以及一些特定于应用程序的属性。任何用户都可以编辑其配置文件以从名为EditProfileViewController的视图控制器更新信息 现在我的问题是:最好从EditProfileViewController、user或其他

我正在创建一个与Firestore数据库交互的应用程序。到目前为止,我有一个单例类,
DatabaseManager
,它拥有与Firestore数据库相关的所有方法(即get/post方法)

我有一个名为
User
的用户模型,它的属性包括
name
email
photoURL
,以及一些特定于应用程序的属性。任何用户都可以编辑其配置文件以从名为
EditProfileViewController
的视图控制器更新信息

现在我的问题是:最好从
EditProfileViewController
user
或其他地方调用
DatabaseManager.shared.updateInfo(forUser:user)
(其中
user
user
实例)吗


很抱歉,如果这是一个明显的问题,但在应用程序中有很多点我需要类似的逻辑,所以我想知道什么是最好的设计。此外,我确信这个问题与MVC的关系要比Firebase/Swift的关系更大。

您使用单例来包含所有Firestore逻辑有什么原因吗?用户模型应该包含updateInfo方法

以下是我在Firestore中使用的一个示例:

class Group {

    // can read the var anywhere, but an only set value in this class
    private(set) var groupName: String!
    private(set) var guestsInGroup: Int!
    private(set) var joinedGroup: Bool!
    private(set) var timeStampGroupCreated: Date!
    private(set) var documentId: String!

    init(groupName: String, guestsInGroup: Int, joinedGroup: Bool, timeStampGroupCreated: Date, documentId: String) {
        self.groupName = groupName
        self.guestsInGroup = guestsInGroup
        self.joinedGroup = joinedGroup
        self.timeStampGroupCreated = timeStampGroupCreated
        self.documentId = documentId
    }


    // method to parse Firestore data to array, that table view will display
    class func parseData(snapshot: QuerySnapshot?) -> [Group]{
        var groups = [Group]()

        guard let snap = snapshot else { return groups }
        for document in snap.documents {
            let data = document.data()
            let groupName = data[GROUP_NAME] as? String ?? "No Group Name"
            let guestsInGroup = data[GUESTS_IN_GROUP] as? Int ?? 0
            let joinedGroup = data[JOINED_GROUP] as? Bool ?? false
            let timeStampGroupCreated = data[TIMESTAMP_GROUP_CREATED] as? Date ?? Date()
            let documentId = document.documentID

            // add objects with fetched data into thoughts array
            let newGroup = Group(groupName: groupName, guestsInGroup: guestsInGroup, joinedGroup: joinedGroup, timeStampGroupCreated: timeStampGroupCreated, documentId: documentId)

            groups.append(newGroup)
        }
        return groups
    }
}
有几点想法:

  • 与其直接使用,
    DatabaseManager.shared.update(for:)
    访问单例,我可以使用数据库管理器的属性,用
    DatabaseManager.shared
    初始化/注入它,并使用该引用与数据库交互,例如,
    dataManager.update(for:)
    。目标是允许您的单元测试在必要时模拟数据库管理器

  • 我不希望视图控制器直接与数据库管理器进行交互。我们中的许多人认为视图控制器,它直接与UIKIT/AppKIT对象交互,作为MVC/MVP/MVVM/任何更广泛的“V”的一部分。我们经常将业务逻辑(包括与数据库管理器的交互)从视图控制器中分离出来

    我个人也不会把它埋在
    User
    对象下。我将它放在数据库管理器的扩展中,并从视图模型、演示者或任何您个人希望使用业务逻辑调用该对象的对象调用它


  • “用户模型应该包含updateInfo方法”-为什么?我的项目的另一个目标是尝试在尽可能少的地方包含任何与任何Firebase类/对象/任何内容相关的内容,以使迁移到自定义后端变得更简单(如果我愿意的话),这样我的模型中就不会有一个方法会接收像
    QuerySnapshot
    这样的Firebase对象。