I've always wanted to do something like
class URLSessionDataTask_Plus: URLSessionDataTask {
var obs: NSKeyValueObservation? = nil
// store the progress observer there
}
which would be very convenient. I don't know how to do it. If instead you do something like
///URLSessionDataTask, plus more!
class URLSessionDataTask_Plus {
var task: URLSessionDataTask? = nil
var obs: NSKeyValueObservation? = nil
}
there's really no advantage, as you anyway have to still maintain that variable externally (or maintain that whole object externally).
Progress observations are a real nuisance to hang on to as you never know how many you'll need or where.
Is there some way to achieve this concept? ->
class URLSessionDataTask_Plus: URLSessionDataTask {
var obs: NSKeyValueObservation? = nil
// store the progress observer there
}
(I note that the same applies even if you use the futuristic async calls .. https://stackoverflow.com/a/78804162/294884 )
FTR, I've been trying out simply adding an objc_getAssociatedObject
.
public var ass_observer: NSKeyValueObservation?
it does seem to work well
as far as I can determine, I cough think it has no leaks
Outline:
extension URLSession {
///Timed data task. Basically a super-data-task which autonomously and
///invisibly does progress, timers, and any other features we need at this
///low level.
static func tDataTask(
with request: URLRequest,
completionHandler: @escaping @Sendable (Data?, URLResponse?, (any Error)?) -> Void
) {
var _firstbyte = true // (NB is workaround for poor behavior of .progress(
LoggingEtc("Waiting for first byte")
let t = URLSession.shared.dataTask(with: request) { (d, r, e) in
LoggingEtc("All data arrived")
completionHandler(d, r, e)
}
// Setup logging, timers, etc
// Use t.taskIdentifier as needed for uniqueness
t.ass_observer = t.progress.observe(\.fractionCompleted) { progress, _ in
if progress.fractionCompleted < 0.02 { return }
if _firstbyte {
LoggingEtc("First byte arrived")
_firstbyte = false
}
ProgressEtc()
}
t.resume()
}
}
and ...
fileprivate var _key_to_ass_observer: UInt8 = 0
extension URLSessionDataTask {
public var ass_observer: NSKeyValueObservation? {
get {
return objc_getAssociatedObject(self, &_key_to_ass_observer) as? NSKeyValueObservation ?? nil
}
set(newValue) {
objc_setAssociatedObject(self, &_key_to_ass_observer, newValue, .OBJC_ASSOCIATION_RETAIN)
}
}
}
Call thus from your API singleton - fire and forget, nothing to retain, etc.
URLSession.tDataTask(with: request) { (data, response, error) in
.. 1, error handling
.. 2, parsing
.. 3, update databases, convert bitcoin, whatever
.. 4, report to whoever called you as relevant
DispatchQueue.main.async { completionOnMain?(200, []) }
}