创建可用于整个iOS应用程序的网络侦听器

时间:2018-12-05 21:26:15

标签: ios swift firebase google-cloud-firestore

我正在使用Firebase开发iOS应用。我的根视图控制器是UITabBarController

上述TabBar中的所有控制器都需要侦听Firebase Firestore中的User文档,但是在每个侦听器中创建侦听器似乎并不是最有效的方法。

我知道我可以像这样在CustomTabBarController中创建侦听器:

import UIKit
import FirebaseFirestore

class CustomTabBarController: UITabBarController {

    var userListener: ListenerRegistration?
    var user: User? // User is a custom class

    override func viewDidAppear(_ animated: Bool) {
        let userID = UserDefaults.standard.value(forKey: "id") as! String

        userListener = Firestore.firestore().document("users/\(userID)").addSnapshotListener { (document, error) in
            if let document = document {
                self.user = User(firebaseDocument: document)
            } else {
                // handle error!
            }
        }
    }

    override func viewDidDisappear(_ animated: Bool) {
        if let listener = userListener {
            listener.remove()
        }
    }

}

,然后从所有user访问该ChildViewController属性,如下所示:

class ChildViewController: UIViewController {

    var user: User?

    override func viewDidLoad() {
        super.viewDidLoad()

        let customTabBarController = tabBarController as! CustomTabBarController
        self.user = customTabBarController.user
    }
}

我发现这种方法存在两个问题:

  1. 由于user中的ChildViewController属性仅在viewDidLoad方法中设置,因此不会更新。
  2. 我不认为CustomTabBarController是处理侦听器失败的地方。不同的ChildViewController将有不同的处理方式。

问题:创建能够更新需要其结果的任何UIVIewController的侦听器的我有哪些选择?我是在正确的道路上吗,或者我可以使用AppDelegate甚至是Singleton来实现这一目标。

谢谢!

2 个答案:

答案 0 :(得分:1)

在您当前的班级中,您可以使用以下方式访问所有vcs

self.viewControllers 

并通过强制转换获得新的用户更新时应用所需的更新,或使用以下方法听用户

var ob:NSKeyValueObservation! 

// in viewDidLoad
let tab = self.tabBarcontroller as! CustomTabBarController
ob = tab.observe(\.user, options: [.new]) { (tab, change) in
 //
}

在每个孩子的内部,或者您可以使用NotificationCenter进行1-M观察,出于分离目的,请考虑一下用户

 class Service {

    static let shared = Service()
    var userListener: ListenerRegistration?
    var user: User? // User is a custom class

    func listenToUpdates() {
        let userID = UserDefaults.standard.value(forKey: "id") as! String

        userListener = Firestore.firestore().document("users/\(userID)").addSnapshotListener { (document, error) in
            if let document = document {
                self.user = User(firebaseDocument: document)
            } else {
                // handle error!
            }
        }
    }

 }

然后

 Service.shared.listenToUpdates()

答案 1 :(得分:0)

您可以创建一个服务类,该服务类将处理对Firestore的查询。如果然后要将结果传递给视图控制器,只需调用闭包即可。您可以执行以下操作:

class FirestoreApiService {
    func getFirebaseUser(withId id: String, then completion: @escaping ((Result<User>) -> Void)) {
        Firestore.firestore().document("users/\(userID)").addSnapshotListener { (document, error) in
            if let document = document {
                completion(.success(User(firebaseDocument: document))
            } else {
                completion(.failure(error))
            }
        }
    }
}

Result仅是通用结果枚举:

enum Result<Value> {
    case success(Value)
    case failure(Error)
}

然后在您的ChildViewController中调用方法:

let apiService = FirestoreApiService()
apiService.getFirebaseUser(withId: "12345") { result in
    switch result {
        case .success(let user):
        //handle success
        case .error(let error):
        //handle error
    }
}

请记住,这只是伪代码,未经测试。