Reputation: 3620
In my iOS project, I need to download a file at a specific location on the device, so I can start reading it while it's still being downloaded.
My goal here is to stream an audio file from the start, but I need that audio file to be saved locally at its final location (I don't want the file to be saved in a temporary folder during the download, and then moved to its final location when the download is complete, which apparently is the default behavior).
So here is what I've tried so far:
private var observation: NSKeyValueObservation?
func downloadAudioFile()
{
let url: URL = URL(string: "https://www.demo.com/audiofile.ogg")!
let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
if (error != nil)
{
print(error)
}
else
{
print("download complete")
}
}
observation = task.progress.observe(\.fractionCompleted) {(progress, _) in
print("progression : \(progress)")
}
task.resume()
}
But since I'm quite a beginner in iOS, I don't know how to save the downloaded data while it's downloading.
How can I achieve that?
Thanks.
Upvotes: 2
Views: 5385
Reputation: 3620
OK so here is what I did (it might not be the cleanest solution, but it works):
class Downloader : NSObject, URLSessionDelegate, URLSessionDataDelegate
{
private var session: URLSession!
private var dataTask: URLSessionDataTask!
private var fileUrl: URL!
func download(url: String, fileName: String)
{
// get path of directory
guard let directory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else {
return
}
// create file url
fileUrl = directory.appendingPathComponent(fileName)
// starts download
session = URLSession(configuration: .default, delegate: self, delegateQueue: nil)
var request: URLRequest = try! URLRequest(url: URL(string: url)!)
request.cachePolicy = .reloadIgnoringLocalCacheData
dataTask = session.dataTask(with: request)
dataTask.resume()
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data)
{
writeToFile(data: data)
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse,
completionHandler: (URLSession.ResponseDisposition) -> Void)
{
completionHandler(URLSession.ResponseDisposition.allow)
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)
{
if (error == nil)
{
// download complete without any error
}
else
{
// error during download
}
}
func writeToFile(data: Data)
{
// if file exists then write data
if FileManager.default.fileExists(atPath: fileUrl.path)
{
if let fileHandle = FileHandle(forWritingAtPath: fileUrl.path)
{
// seekToEndOfFile, writes data at the last of file(appends not override)
fileHandle.seekToEndOfFile()
fileHandle.write(data)
fileHandle.closeFile()
}
else
{
// Can't open file to write
}
}
else
{
// if file does not exist write data for the first time
do
{
try data.write(to: fileUrl, options: .atomic)
}
catch
{
// Unable to write in new file
}
}
}
}
Upvotes: 2