[REQ] [Swift] Abstract away URLSession
See original GitHub issueIs your feature request related to a problem? Please describe.
Yes. I’m trying to implement a caching mechanism that basically overrides the URLSession.dataTask
and under the hood it takes the response from the cache (if available) and at the same time loads using the URLSession
itself. Currently, the only way of changing the URLSession
is via override of URLSessionRequestBuilder.createURLSession
(well, I can always write my own RequestBuilder
, but that’d be a lot of duplicated code). So to be able to implement my approach I’d have to subclass URLSession
and override the dataTask
.
The implementation would look like this:
class CacheFirstURLSession: URLSession {
override func dataTask(
with request: URLRequest,
completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void
) -> URLSessionDataTask {
if let cachedResponse = configuration.urlCache?.cachedResponse(for: request) {
completionHandler(cachedResponse.data, cachedResponse.response, nil)
}
return super.dataTask(with: request, completionHandler: completionHandler)
}
}
This is not currently doable (as far as I know, URLSession
s are not subclassable). I tried a couple of times to make a subclass, but it does not work - calling dataTask
crashes the app. Probably because there’s no way to inject configuration into a subclass.
Describe the solution you’d like
So I don’t necessarily need a subclass of the URLSession
, I can go with a wrapper like :
class URLSessionWrapper {
private let wrapped: URLSession
init(with wrapped: URLSession) {
self.wrapped = wrapped
}
}
extension URLSessionWrapper: DataTaskMaking {
func dataTask(
with request: URLRequest,
completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void
) -> URLSessionDataTask {
if let cachedResponse = wrapped.configuration.urlCache?.cachedResponse(for: request) {
completionHandler(cachedResponse.data, cachedResponse.response, nil)
}
return wrapped.dataTask(with: request, completionHandler: completionHandler)
}
}
The only problem that I have now is that the URLSessionRequestBuilder.createURLSession
returns the exact URLSession
. If we’d be able to exchange it into a protocol then my problem is solved.
Here’s an initial idea of what we’d have to do in the URLSessionImplementation.mustache
:
Somewhere at the top (or bottom):
public protocol DataTaskMaking {
func dataTask(
with request: URLRequest,
completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void
) -> URLSessionDataTask
}
extension URLSession: DataTaskMaking {}
And then change the override:
{...} func createURLSession() -> DataTaskMaking {
return defaultURLSession
}
Describe alternatives you’ve considered
So I tried solving the problem with subclassing and extensions which both don’t seem to be feasible in our current architecture. Another possible option is to create my own own RequestBuilder
, but that’d be a lot of duplicated code.
Additional context
Nope
Issue Analytics
- State:
- Created 2 years ago
- Reactions:1
- Comments:9 (8 by maintainers)
Top GitHub Comments
Hello @4brunu, I saw that example in
BearerDecodableRequestBuilder.swift
and yes that works for implementing token refreshing but still subclassing URLSession would be better but unfortunately it is not possible. As @Czajnikowski wrote subclassingfunc dataTask(with request: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask
crashes the app with SIGABORT error. I think it was possible to subclass URLSession some time ago but currently it is not working I just checked with this code which always crashes on call to super.dataTask:and
It also shows a warning that
'init()' was deprecated in iOS 13.0
next toMyURLSession()
and if you open URLSession definition you can also see this in Apple’s code:So it is currently not possible to properly initialize subclassed URLSession and that explains why it crashes if you try to do that. Therefore without abstracting URLSession replacing it by overriding
createURLSession
is currently not very useful. Also this stack overflow topic confirms problems with subclassing URLSession: https://stackoverflow.com/questions/48158484/subclassing-factory-methods-of-urlsession-in-swift If instead of URLSession we could provide anything that confirms to a protocol as proposed by @Czajnikowski then that would solve this problem.Could you please open a PR?