I have an application that (in part) displays the current download speed of a Wi-Fi connection to a user. It does so by opening a URLSession
and downloading a moderate-sized (~10MB) file and measuring the time it took.
Here's that URLSession function:
func testSpeed() {
Globals.shared.dlStartTime = Date()
Globals.shared.DownComplete = false
if Globals.shared.currentSSID == "" {
Globals.shared.bandwidth = 0
Globals.shared.DownComplete = true
} else {
let url = URL(string: [HIDDEN])
let session = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: nil)
let task = session.downloadTask(with: url!)
task.resume()
}
}
public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
Globals.shared.dlFileSize = (Double(totalBytesExpectedToWrite) * 8) / 1000
let progress = (Double(totalBytesWritten) / Double(totalBytesExpectedToWrite)) * 100.0
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "ProcessUpdating"), object: nil, userInfo: ["progress" : progress])
}
public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
let elapsed = Double( Date().timeIntervalSince(Globals.shared.dlStartTime))
Globals.shared.bandwidth = Int(Globals.shared.dlFileSize / elapsed)
Globals.shared.DownComplete = true
Globals.shared.dataUse! += (Globals.shared.dlFileSize! / 8000)
session.invalidateAndCancel()
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "ProcessFinished"), object: nil, userInfo: nil)
}
As you can probably tell by the delegate functions, this all exists in a separate class from the view controller, along with some other small networking functions, like getting IP and SSID. The delegates post notifications that are observed by the view controller.
My ViewController has an NSTimer that calls back to this URLSession every 5 seconds to re-test the speed (but only runs it if the previous one completed). Here's the code for that:
reloadTimer = Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(rescanNetwork), userInfo: nil, repeats: true)
Which calls this function:
func backgroundRescan() {
if Globals.shared.DownComplete {
Networking().testSpeed()
}
}
Which runs the URL Session again, checking, of course, to ensure that the previous had completed.
For some reason, I'm getting a massive buildup of memory use in testing, until the app reaches 2GB of memory use and gets terminated with the console output Message from debugger: Terminated due to memory issue
. This all happens within two minutes of running the app.
I even added session.invalidateAndCancel()
to the completion delegate in a desperate attempt to clear that memory. But it didn't work. Am I missing something?