So I have a class like below
class DownloadOperation: Operation {
private var task : URLSessionDownloadTask!
enum OperationState : Int {
case ready
case executing
case finished
}
// default state is ready (when the operation is created)
private var state : OperationState = .ready {
willSet {
self.willChangeValue(forKey: "isExecuting")
self.willChangeValue(forKey: "isFinished")
}
didSet {
self.didChangeValue(forKey: "isExecuting")
self.didChangeValue(forKey: "isFinished")
}
}
override var isReady: Bool { return state == .ready }
override var isExecuting: Bool { return state == .executing }
override var isFinished: Bool { return state == .finished }
init(
session: URLSession,
downloadTaskURL: URL,
item: ItemModel,
completionHandler: ((URL?, URLResponse?, ItemModel, Error?) -> Void)?
) {
super.init()
// use weak self to prevent retain cycle
task = session.downloadTask(
with: downloadTaskURL, completionHandler: { [weak self] (localURL, response, error) in
/*
if there is a custom completionHandler defined,
pass the result gotten in downloadTask's completionHandler to the
custom completionHandler
*/
if let completionHandler = completionHandler {
// localURL is the temporary URL the downloaded file is located
completionHandler(localURL, response, item, error)
}
/*
set the operation state to finished once
the download task is completed or have error
*/
self?.state = .finished
})
}
override func start() {
/*
if the operation or queue got cancelled even
before the operation has started, set the
operation state to finished and return
*/
if(self.isCancelled) {
state = .finished
return
}
// set the state to executing
state = .executing
// start the downloading
self.task.resume()
}
override func cancel() {
super.cancel()
// cancel the downloading
self.task.cancel()
}
}
I would like to call it in async func, but I'm having difficulties with converting it to asyn func
func getItemsAsync() async {
requestStatus = .pending
do {
let feedsData = try await dataService.fetchAllFeedsAsync()
for index in feedsData.indices {
var item = feedsData[index]
// make sure Item has a URL
guard let videoURL = item.url else { return }
let operation = DownloadOperation(
session: URLSession.shared,
downloadTaskURL: videoURL,
item: item,
completionHandler: { [weak self] (localURL, response, item, error) in
guard let tempUrl = localURL else { return }
let saveResult = self?.fileManagerService.saveInTemp(tempUrl, fileName: videoURL.lastPathComponent)
switch saveResult {
case .success(let savedURL):
let newItem: ItemModel = .init(
id: item.id,
player: AVPlayer(url: savedURL)
)
await MainActor.run(body: {
self?.items.append(newItem)
if items.count ?? 0 > 1 {
// once first video is downloaded, use all device cores to fetch next videos
// all newest iOS devices has 6 cores
downloadQueue.setMaxConcurrentOperationCount(.max)
}
})
case .none: break
case .failure(_):
EventTracking().track("Video download fail", [
"id": item.id,
"ulr": videoURL.absoluteString.decodeURL()
])
}
})
let fileCaheURL = downloadQueue.queueDownloadIfFileNotExists2(videoURL, operation)
if let fileCaheURL = fileCaheURL {
// ... do some other magic
}
}
} catch let error {
requestStatus = .error
errorMessage = error.localizedDescription
}
}