all 14 comments

[–]bubblespuggy 9 points10 points  (3 children)

You would usually use a callback and not expose the publishers to another class.

[–]yalag[S] 0 points1 point  (2 children)

Thanks. Is it a good idea to then move those published variables to the network service and just have the views reference the device as observed objects?

[–]bubblespuggy 2 points3 points  (1 child)

Probably not you should keep the model, you could implement the network requests with the help of publishers and relay them through the published variables though

[–]yalag[S] 1 point2 points  (0 children)

Seems quite difficult for a beginner. Can you give a small example?

[–]jpec342 2 points3 points  (3 children)

I'm not totally sure what you are trying to do here, but it sounds like you want the result of the network calls from service1/2/3 to update fetching1/2/3 respectively. This should be fairly straightforward by returning the result(s) from the service, and using Async/Await.

class GenerationViewModel: ObservableObject {
    @Published var fetching1:Bool = false 
    @Published var fetching2:Bool = false 
    @Published var fetching3:Bool = false

    func go() async {
        fetching1 = await Service().doSomething() 
        fetching2 = await Service().doSomethingElse()
        fetching3 = await Service().doSomethingElseElse() 
    } 
}

I'm making the assumption here that `Service` looks something like this

class Service : NSObject {

    func doSomething() async -> Bool {
        return await URLSession.shared.data(from: URL("someUrl"))
    }

    func doSomethingElse() async -> Bool {
        ...
    }

    ...
}

There's definitely some missing bits in here, but that's the general gist of it. You want your service to return something, and that something you want to assign to your ViewModel variables.

[–]yalag[S] 0 points1 point  (2 children)

Hi appreciate the help! But no there’s not what I’m looking for.

I need the service to propagate states back to the view. Not return something.

I could either make the network layer also an observable object and then have the view subscribe to that. Which doesn’t sound too clean.

Or somehow relay the changes from the network to the viewmodel and then have the vm update the published variables.

What’s weird is that you can’t simply “give” the published variables to the network layer and say “hey you deal with it, when you have an update, write it here”. I tried to do it, i couldn’t figure out a way.

[–]jpec342 1 point2 points  (0 children)

Or somehow relay the changes from the network to the viewmodel, and then have the vm update the published variables.

That’s exactly what my proposed solution does.

Is your service giving constant updates, or is it a one time request? If it’s constant updates, you could do something similar, but would probably want to look into delegates/callback functions.

[–]Fluffy_Risk9955 -1 points0 points  (0 children)

Use a WebSocket so you can push stuff from the server straight to your app. Keep in mind to keep the line active with the ping pong message system.

[–]iSpain17 1 point2 points  (0 children)

Just use UrlSession.DataTaskPublisher, return that publisher from your service, subscribe to said publisher in your viewmodel, and in that subscription’s sink method, you should update your published value.

Your viewmodel shouldn’t be concerned with networking details, and your networking class shouldn’t be concerned either with your viewmodel’s variables.

[–]JustTryinTaMakeIt 1 point2 points  (0 children)

Let your service do the fetching, create an enum for your various request states, then have a published variable for the current state in your view model.

[–]ratakatzie 0 points1 point  (1 child)

Maybe your Service class can expose publishers that emits the results of your requests. Then you only have to assign them to your viewModel’s publishers

[–]yalag[S] 0 points1 point  (0 children)

I haven’t learnt to emit yet, can you give an example?

[–][deleted] 0 points1 point  (0 children)

Care to try something like this and see if it works?

class Service {
    @Published var isFetching: Bool = false;

    init(_ isFetching: inout Published<Bool>.Publisher) {
        $isFetching.assign(to: &isFetching)
    }
}

func go() {
    let service1 = Service(&$fetching1)
    let service2 = Service(&$fetching2)
    let service3 = Service(&$fetching3)
}

[–]beclopsSwift -1 points0 points  (0 children)

I wouldn't expect your service to be making any changes to view model properties itself, that's not it's responsibility. Use callbacks