I am using Dependency injection, Coordinators & the MVP design pattern.
Once a user logs into my app, I get their account object from Firestore in my AppCoordinator. This account object and other services are injected into my 'TabBarCoodinator' which injects them into all child coordinators and they do the same with presenters, etc.
init(_ navigationController: UINavigationController,
_ firestoreRepository: FirestoreRepositoryProtocol,
_ firebaseCloudStorageService: FirebaseCloudStorageServiceProtocol,
_ firebaseCrashlyticsService: FirebaseCrashlyticsServiceProtocol,
_ notificationService: NotificationServiceProtocol,
_ account: FIRAccount,
_ alertHandlerService: AlertHandlerServiceProtocol) {
self.navigationController = navigationController
super.init()
self.coord1 = Coord1(
firestoreRepository,
firebaseCloudStorageService,
geoLocationService,
alertHandlerService,
account,
delegate: self)
self.coord2 = Coord2(
firestoreRepository,
notificationService,
alertHandlerService,
account)
self.coord3 = Coord3(
firestoreRepository,
firebaseCloudStorageService,
firebaseCrashlyticsService,
geoLocationService,
alertHandlerService,
account,
delegate: self)
}
I have set up a listener in the AppCoordinator to listen for changes to the account object. When changes occur, I want this to propagate down into all other classes that the account is injected into so no objects have an outdated account object.
The problem I am facing is how to propagate account object changes to all children classes.
Each part of the app, such as the 'EditProfilePresenter', plays a role in editing a piece of the account object. An edit is made to the account object in a particular presenter and changes are pushed to Firestore.
This results in a huge issue, all account objects that have been injected into other coordinators and presenters from the AppCoordinator are now out of date. The only up-to-date object is the 'EditProfilePresenter' account object and the one held in the AppCoordinator due to the listener.
How can I either propagate the updated information to all objects using the account object or, how should I set up my objects to have a single source of truth for a user account object? Ideally, I want the injected account to reference the original stored on the AppCoordinator, not a copy or clone of it.
Things I have considered:
Set up three individual listeners for the three main parts of the app. Each listener would manage that slice of the apps account object. However, this results in 3 reads for a single update which is not great for scalability at all.
Store the account object on the FirestoreRepositoryService. Most classes requiring this service use the account object and it is instantiated in the app coordinator so should be shared throughout all classes. However, this sounds bad as it breaks the responsibility of the service simply performing Firestore related requests.
Use a singleton to manage the account state which is shared and used by all classes needing it. This would mean the account object is always kept updated in a single place with a single listener. However, this would drastically reduce testability & readability due to the account object no longer being injected as well as creating tight coupling throughout the whole app on a single object that whose state is shared everywhere.
Look into restructuring the account object where information is split into specific sections of the account object. Ideally, one tab should only deal with its assigned slice of the information and would not have the whole account object. Rather, it would have a sub-collection within the account object. However, shared information that is commonly used everywhere, such as a name, would either be stored on the account object or in a sub-collection resulting in even more reads required to maintain data and a few other drawbacks.
Setup a notification to be sent out every time the app coordinator receives an account update and register for this notification in every object that uses the account object. However, this again feels like a really poor way of dealing with the issue due to the overhead of needing to ensure every object is registered to this notification or the data will be inconsistent.
I am really not sure what to do, any help on how to deal with this would be appreciated!