Создание сетевого слушателя, доступного для всего приложения iOS - PullRequest
0 голосов
/ 06 декабря 2018

Я разрабатываю приложение для iOS с Firebase.Мой контроллер корневого представления - это UITabBarController.

Все контроллеры в указанном TabBar должны прослушивать User документ в Firestore Firebase, но создание слушателя в каждом из них не кажетсянаиболее эффективный способ сделать это.

Я знаю, что мог бы создать слушателя в 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 голосов
/ 06 декабря 2018

Из вашего текущего класса вы можете получить доступ ко всем 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-М, в целях разделения воспринимайте пользователя как

 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()
0 голосов
/ 06 декабря 2018

Вы можете создать класс обслуживания, который будет обрабатывать ваши запросы до 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:

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
    }
}

Имейте в виду, что это просто псевдокод, и он не тестируется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...