BottleRocketStudios / iOS-Hyperspace

An extremely lightweight wrapper around URLSession to make working with APIs a breeze.
Apache License 2.0
47 stars 17 forks source link

Feature/cancellation #85

Closed wmcginty closed 2 years ago

wmcginty commented 5 years ago

OK, as promised here is a draft PR for what a revamp to the cancellation mechanism might look like. I have somewhat implemented a CancellationSource into the NetworkService and by extension the BackendService.

1) When executing the request, keep and store a CancellationSource:

let source = CancellationSource()
preferredBackendService.execute(request: getUserRequest, cancellationToken: source.token) { [weak self] result in
            debugPrint("Get user result: \(result)")

            switch result {
            case .success(let user):
                self?.presentAlert(titled: "Fetched user", message: "\(user)")
            case .failure(let error):
                self?.presentAlert(titled: "Error", message: "\(error)")
      }
}

At this point we could definitely provide a customization point into the creation of the token if needed, for instance:

source.token(with: UUID())

Inside Hyperspace, the BackendService simply passes the CancellationSource.Token into the NetworkService where it is used in generation of the request:

public func execute(request: URLRequest, cancellationToken: CancellationSource.Token? = nil, completion: @escaping NetworkServiceCompletion) {
    let task = session.dataTask(with: request) { [weak self] (data, response, error) in
        //completion handler
    }

    cancellationToken?.register { task.cancel() }
    //more implementation
}

At this point, all you have to do from the client of the BackendService has to do is call:

source.cancel()

This will cancel all the tokens that have been generated by the given source. In this specific case, this results in a result of : .failure(cancelled)

wmcginty commented 5 years ago

@tylermilner @earlgaspard @GrandLarseny thoughts?

wmcginty commented 5 years ago

Another thing I've been thinking about recently that could work well with a system like this is priority. I've got a use case at the moment where the URLSessionTask.Priority of each of my requests can change drastically based on a user's scroll position (if it shouldn't be cancelled altogether). After a quick think, a token like system that represents the task in flight could work as well.

Just a thought 🤷‍♂️