Function does not wait until the data is downloaded
The other answer is not a good replacement for the code you already had. A better way would be to continue using NSURLSession's data tasks to keep the download operation asynchronous and adding your own callback block to the method. You need to understand that the contents of the download task's block are not executed before you return from your method. Just look at where the call to resume() is for further evidence.
Instead, I recommend something like this:
func getImageFromServerById(imageId: String, completion: ((image: UIImage?) -> Void)) {
let url:String = "https://dummyUrl.com/\(imageId).jpg"
let task = NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: url)!) {(data, response, error) in
completion(image: UIImage(data: data))
}
task.resume()
}
Which can be called like this
getImageFromServerById("some string") { image in
dispatch_async(dispatch_get_main_queue()) {
// go to something on the main thread with the image like setting to UIImageView
}
}
How to make the function wait until response comes back
You can use the async/await pattern with Promises, something like this:
zipFile = new JSZip();
async mapZip() {
try {
var response = await this.exportIcsReportInJSONFormat();
console.log("JSONFile", response)
this.jsonFile = response;
this.zipFile.file("ics-report_.json", response, { binary: true });
var content = await this.zipFile.generateAsync({ type: "blob" });
saveAs(content, "example.zip");
}
catch {
...
}
}
exportIcsReportInJSONFormat() {
this.icsService.getICSReport().toPromise();
}
Protractor test does not wait for file to be downloaded
await fs.existsSync(excelFile);
is only waiting for the fs.existsSync function to complete (which returns true if the file does exist), not actually waiting for the file to exist.
You could try adding a browser.wait() which would wait the file to download like so.
await browser.wait(async function () {
return await fs.existsSync(excelFile);
}, 30*1000, "File has not downloaded within 30 seconds")
Pause a for loop until function is completed
None of your functions justifies the async
keyword (if you're not using await
, using async
is nonsense).
But all of your functions are missing return
. You need to return the promises you create in a function.
Compare - every code path ends in return
:
// returns a promise for whatever downloadFile() produces
function getFile(version) {
return axios.request({ /* ... */ }).then((response) => {
return downloadFile(version, response.data.location);
}).catch(err => {
return {error: "Download failed", version, err};
});
}
// downloadFile() also returns a promise, so we return that
function downloadFile(version, data) {
if (version && data) {
const downloader = new Downloader({ /* ... */ });
return downloader.download();
}
throw new Error("Invalid arguments");
};
// `downloads` will be an array of promises, we can wait for them with `Promise.all()`
function main() {
const downloads = [];
for (let i = 7990; i < 7995; i++) {
downloads.push(getFile(i));
}
Promise.all(downloads).then((results) => {
// all downloads are done
}).catch(err => {
console.log(err);
});
}
You probably don't want to daisy-chain the downloads. You just want to wait until all are done. Promise.all()
does that.
Swift: wait for app execution till file downloads ends
You have to make downloadFile
really async
by using the appropriate async URLSession
API. The completion handler API doesn't wait
.
func downloadFile (fileOnServer: String, fileOnDevice: URL) async throws {
guard let dataURL = URL(string: fileOnServer) else { throw URLError(.badURL) }
let (dataTempFileUrl, _) = try await URLSession.shared.download(from: dataURL)
try FileManager.default.moveItem(at: dataTempFileUrl, to: fileOnDevice)
}
In the task
you have add a do - catch
block to handle the error(s)
.task()
{
do {
print ("START downloadFile() ")
try await downloadFile(fileOnServer: htmlLinkForJSON, fileOnDevice: downloadedJSON)
try await downloadFile(fileOnServer: htmlLinkForCategories, fileOnDevice: downloadedCategories)
print ("END downloadFile()")
print ("---------")
print ("Start checkSavedFile()")
checkSavedFile(file: downloadedJSON)
checkSavedFile(file: downloadedCategories)
print ("END checkSavedFile()")
print ("---------")
} catch {
print(error)
}
}
Wait for async function and promises in it to finish
One option would be to have a loop that goes over the images and processes one after another. To then run multiple processings in parallel, start multiple loops:
// Goes over the "data" array, calls and waits for each "task" and processes "runnerCount" tasks in parallel
function inParallel(task, data, runnerCount) {
let i = 0, results = [];
async function runner() {
while(i < data.length) {
const pos = i++; // be aware: concurrent modification of i
const entry = data[pos];
results[pos] = await task(entry);
}
}
const runners = Array.from({ length: runnerCount }, runner);
return Promise.all(runners).then(() => results);
}
To be used as:
const delay = ms => new Promise(res => setTimeout(res, ms));
inParallel(async time => {
console.log(`Timer for ${time}ms starts`);
await delay(time);
console.log(`Timer for ${time}ms ends`);
}, [5000, 6000, 1000]/*ms*/, 2/*in parallel*/);
Related Topics
Access Input from Uialertcontroller
Swiftui - Navigation Bar Button Not Clickable After Sheet Has Been Presented
Swift Write/Save/Move a Document File to Icloud Drive
How to Check If a Property Value Exists in Array of Objects in Swift
How to Determine the Type of a Variable in Swift
Uicollectionview - Resizing Cells on Device Rotate - Swift
Dispatchsourcetimer and Swift 3.0
Upvote/Downvote System Within Swift via Firebase
Override Func Error in Swift 2
Building Pure Swift Cocoa Touch Framework
Swift - Unit Testing Private Variables and Methods
A Swift Protocol Requirement That Can Only Be Satisfied by Using a Final Class
Uiapplication.Shared.Delegate Equivalent for Scenedelegate Xcode11
Why Is There No Universal Base Class in Swift
Is Swiftui Backwards-Compatible With iOS 12.X and Older