Pass data to dispatchGroup.notify in Swift

325 Views Asked by At

I'm downloading some JSON from an API, but there is another prerequisite (an animation) that must be complete before we move to the next screen.

I've decided to use DispatchGroup to do this, but also need to have a reload as well.

I've come up with a solution that uses a completion handler that is either dispatchGroup.leave or simply moving to the next screen, since we only need to download the data once.

let dispatchGroup = DispatchGroup()
var userName: String?

func fetchData() {
    dispatchGroup.enter()
    dispatchGroup.enter()
    
    resolveDataRequirements(dispatchGroup.leave)
    
    dispatchGroup.notify(queue: .main) { [weak self] in
        self?.moveToNextScreen()
    }
}

func resolveDataRequirements(_ completion: @escaping(() -> Void)) {
    api.resolve { [weak self] result in
        switch result {
        case .success(let user):
            self?.userName = user
            completion()
        case .failure:
            break
        }
    }
}

func moveToNextScreen() {
    // move to next screen, but passes the user
}

// reload data, and once the data is downloaded move to next screen
func reloadData() {
    resolveDataRequirements(moveToNextScreen)
}


// the user might choose to fetch data
fetchData()
// now if the user wanted to reload
reloadData()

Now the problem is that this is in a view model - so the user String is effectively a state that I wish to eradicate.

Is there any way I can pass the user String to dispatchGroup.notify or similar?

1

There are 1 best solutions below

4
On

You can use inout properties and change userName scope like this:

func fetchData() {
    var userName = ""
    dispatchGroup.enter()
    dispatchGroup.enter()
    
    resolveDataRequirements(dispatchGroup.leave, &userName)
    
    dispatchGroup.notify(queue: .main) { [weak self] in
        self?.moveToNextScreen(userName)
    }
}

func resolveDataRequirements(_ completion: @escaping(() -> Void), _ userName: inout String) {
    api.resolve { [weak self] result in
        switch result {
        case .success(let user):
            userName = user
            completion()
        case .failure:
            break
        }
    }
}

func moveToNextScreen(_ userName: String) {
    print(userName)
}

I just don't understand why you are calling enter() twice and leave() just once