I wanted to translate this in swift :
dispatch_async(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL: googleRequestURL];
[self performSelectorOnMainThread:#selector(fetchedData:) withObject:data waitUntilDone:YES];
});
It's for using google places api.
I wondering about using a simple NSURLSession request but it seems that the dataWithContentsOfURL do the job of an NSURLSession request ?
Someone ?
dataWithContentsOfURL is discouraged. You should use NSURLSession for asynchronous downloads, or if you prefer the simpler NSURLConnection.
The delegate callbacks tell the main thread when the download is finished - so no need to engage with Great Central Dispatch APIs.
Mundi is right that the better tool here is NSURLSession. But your code can work; just need to use GCD correctly, and deal with the fact that it might fail:
dispatch_async(kBgQueue) {
if let data = NSData.dataWithContentsOfURL(googleRequestURL) {
dispatch_sync(dispatch_get_main_queue()) { self.fetchedData(data) }
} else {
// Here's the problem with dataWithContentsOfURL. You had an error, but you
// don't know what it was. I guess you'll do something here...
}
}
Related
Trying to make rest api calls from an iOS app using this method http://spring.io/guides/gs/consuming-rest-ios/
Need to make 3 api calls one after another and need to utilize part of the json result in the subsequent api call. How should I proceed?
iOS app is been developed using Objective-C
Setup a background thread like this:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
<#code#>
});
And execute your API calls synchronously within it. It might look something like this:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
id dataOne = [self apiCallOne];
id dataTwo = [self apiCallTwoWithDataOne:dataOne];
id dataThree = [self apiCallThreeWithDataTwo:dataTwo];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Completion with data: %#", dataThree);
});
});
Make sure to use [NSURLConnection sendSynchronousRequest: ...]; as opposed to [NSURLConnection sendAsynchronousRequest: ...];
I'm trying to save a NSDictionary containing 30 images. I'm calling the method to save the dictionary in the viewDidDisappear of my ViewController. The problem is that the UI freeze while saving. It's a small lag, less than a second, but a bit annoying. Do you have any ideas to make it more fluid? Maybe I should save the dictionary asynchronously, maybe in a block, but I don't know well how to use them.
Here's my saving et getting methods :
+ (NSDictionary*)getProgramImages{
NSString *path = [DataManager getProgramImagesFileDirectory];
NSDictionary *programImages = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
return programImages;
}
+ (void)saveProgramImages:(NSDictionary*)programImages{
NSString *path = [DataManager getProgramImagesFileDirectory];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:programImages];
[data writeToFile:path options:NSDataWritingAtomic error:nil];
}
Thanks a lot for your help!
Boris
You could try wrapping your function call using the below code, which uses Grand Central Dispatch to run that code on a background thread. Not able to test at the moment to see if that could solve your issue or not.
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// call that function inside here
});
Maybe dispatch_async could help you to smoothen the code running on main thread.
dispatch_async(dispatch_get_main_queue(),^{
//your code goes here
});
There're many ways to solve your problem. You should read this
Concurrency Programming
Grand Central Dispatch is a good choice.
I am needing to perform a very simple background check for my iOS app. It needs to just make one call to my web server and check the number it retrieves against something in my app. Is it possible to do that kind of background check? If so what can I do to put it together?
EDIT
To clarify what I mean by background: I am meaning background on the phone. When the app is not present. Is it possible to do this request in the background? Obviously with the app not being completely closed out from multitasking.
This sounds like the perfect sort of thing for NSOperationQueue.
http://www.raywenderlich.com/19788/how-to-use-nsoperations-and-nsoperationqueues
You can write an operation and then put it on the queue when you need it.
Alternatively, and more simply, you can just do a really simple asynchronous call.
+ (NSArray *) myGetRequest: (NSURL *) url{
NSArray *json = [[NSArray alloc] init];
NSData* data = [NSData dataWithContentsOfURL:
url];
NSError *error;
if (data)
json = [[NSArray alloc] initWithArray:[NSJSONSerialization
JSONObjectWithData:data
options:kNilOptions
error:&error]];
if (error)
NSLog(#"%#", error)
return json;
}
and then put it in a simple dispatch block...
dispatch_queue_t downloadQueueA = dispatch_queue_create("updater", NULL);
dispatch_async(downloadQueueA, ^{
// stuff done here will happen in the background
NSArray * arrayOfData = [self myGetRequest: myURL];
// could be array... dictionary... whatever, you control this by returning the type of data model you want from the server formatted as JSON data
NSString * stringValue = arrayOfData[index];
dispatch_async(dispatch_get_main_queue(), ^{
// perform checking here and do whatever updating you need to do based on the data
});
});
There are many way to check your server and retrieve data.
Here my suggestion:
Create the file containing your data on the server (e.g. Data.txt)
Use NSURLRequest to create a request to Data.txt
Use connectionDidFinishLoading to get data from Data.txt
Put data from Data.txt in a NSArray
Work/compare the array and do your logic
If your server is fast and you have to get just one number, you can do it in the main tread, otherwise use:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
// your request here
});
to work in a different tread as requested.
And remember to check if internet connection and your server are available with something like Reachability and manage connection error with NSURLRequest delegate
You should be able to do that using Grand Central Dispatch: https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
Take a look at this tutorial Multithreading and Grand Central Dispatch on iOS.
http://www.raywenderlich.com/4295/multithreading-and-grand-central-dispatch-on-ios-for-beginners-tutorial
I'm trying to download information in background from a url.
I've read about GCD, Runloops and threads and decided that dispatc_async is my way to go.
After receiving data I aalso want to update the gui.
But... the NSUrlConnection don't seem to start at all. The delegate don't receive any calls.
I'v used this NSUrlRequest and NSUrlConnection in a synchronous way and the delegate got the data excpected.
Here is my code, a method in a viewcontroller;
- (void)dispatch: (NSURLRequest *) pRequest respondTo: (VivaQuery *) pQuery {
dispatch_queue_t downloadQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(downloadQueue, ^{
NSURLConnection *tConnectionResponse =[[NSURLConnection alloc] initWithRequest: pRequest delegate: pQuery];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Got to main thread.");
[pQuery requestEnd]; // Will update gui, i e aUIView setNeedsDisplay
});
});
}
Anyone got an idea?
Thanks in advance.
Kind regards,
Jan Gifvars
Stockholm
NSUrlConnection does its work asynchronously on it's own background thread so you do not need to create it in a background thread.
This question already has answers here:
loading images from a background thread using blocks
(3 answers)
Closed 8 years ago.
I'm trying to download an image from a website and save it as a UIImage but if the user has low connection this can take forever... how can I download it in the background so the user can keep using the app in the meantime?
here is the code:
theIcon.image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://myWebsite.com/Icon.png"]]];
Use GCD.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
// do my background code
dispatch_async(dispatch_get_main_queue(), ^{
// do handling on main thread when done!
});
});
Use AFNetworking.
[imageView setImageWithURL:
[NSURL URLWithString:#"http://i.imgur.com/r4uwx.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder-avatar"]];
You can perform the selector in background thread while the main foreground thread runs.
[self performSelectorInBackground:#selector(downloadFile) withObject:nil];
- (void) downloadFile {
//download file
//you can show UIAlertView when done
}
In your - (void) downloadFile you can download this big file.
and have an activity indicator show (or not). You can have the activity Indicator become not hidden or hidden and have it startAnimating and stopAnimating will make it spin and stop. This can be referenced from the foreground and background processes.
The quick and dirty way:
NSMutableRequest* request = ... ;
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse* response, NSData* data, NSError* error) {
if (!error) {
// do something with the response data.
}
}];
This approach is sufficient for "a prove of concept", toy programs with simplistic insecure connections, Apple samples, and for hobbyists learning iOS for fun, and for samples which demonstrate anti-patterns ("How you should do it, not!").
If you want a solid approach you need to use NSURLConnection in asynchronous mode and implement the delegates - or use a third party library. ;)