hmlongco / Factory

A new approach to Container-Based Dependency Injection for Swift and SwiftUI.
MIT License
1.83k stars 115 forks source link

Question: Can a Singleton Factory be Observable? (Cause View to re-render?) #109

Closed samskinner32 closed 1 year ago

samskinner32 commented 1 year ago

Hello! I am fairly new to Swift/SwiftUI/Factory, so this may be a non-sensical or bad question, forgive me!

I am using Factory (v1.2.8) to inject various services into the app, some of which are singletons that hold data that I want to access on different screens. E.g. I have a FriendService that holds an array of [Friend] and also has functions to fetch and update this array. What I WANT to happen is that if I'm on a View and this array updates, I'd like the View to re-render. Right now, I'm having to manually trigger a re-render for the View's data to show the latest service data. (Hopefully that makes sense so far...)

Very simplified relevant code here:

My Service:

protocol FriendServiceInterface {
    var friends: [Friend]? { get }
...

class FriendService: NSObject, FriendServiceInterface {
  var friends: [Friend]?

  func getFriends() async {
    do {
      friends = try await networkService.fetchFriends()
    } catch {
      print("Error fetching friends list: ", error)
    }
  }
...

My Container:

static let friendService = Factory<FriendServiceInterface>(scope: .singleton) { FriendService() }

My View:

@Injected(Container.friendService) var friendService: any FriendServiceInterface

var friends: [Friend] {
  return friendService.friends ?? []
}

--

In my ideal world, I'd want it to be like...

class FriendService: NSObject, FriendServiceInterface, ObservableObject {
  @Published var friends: [Friend]?

so that my View reacts to changes when friends updates.

Is that possible? Let me know if this needs more context or makes no sense. Really appreciate any responses. Thank you! :)

hmlongco commented 1 year ago

Some of that is covered in the documentation on InjectedObject

But the problem with ObservableObject and protocols is that there are associated type issues, which I wrote about here.

The real solution is not to mix view models and protocols.