NSString *jsonPath = [[NSBundle mainBundle] pathForResource:#"CRN_JSON"
ofType:#"json"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
data = [NSData dataWithContentsOfURL:
[NSURL URLWithString:#"http://properfrattire.com/Classifi/CRN_JSON.json"]];
[self performSelectorOnMainThread:#selector(fetchedData:)
withObject:data waitUntilDone:YES];
});
My data variable is nil after running this code. If you follow the link you'll see that it is a JSON file. I've run the function with this exact same file locally but it is not able to obtain the data at the given URL without error.
Not sure why you're nesting calls to URLWithString:
[NSURL URLWithString:[NSURL URLWithString:#"http://properfrattire.com/Classifi/CRN_JSON.json"]]];
Once will do:
[NSURL URLWithString:#"http://properfrattire.com/Classifi/CRN_JSON.json"];
Also, you should use dataWithContentsOfURL:options:error: so you can see any error.
Related
I want to save multiple images to my documents path folder. My web service returns more than one image url path and i want to save each image to my documents folder.This process working successfully, but my view FREEZES at this time(converting image url to NSData).I am using following code.How to avoid this issue?
NSData * data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[usersArray objectAtIndex:i]objectForKey:#"message"]]];
NSString *localImgpath = [directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#",imageName, #"png"]];
[data writeToFile:localImgpath atomically:YES];
You would want to process that in a background thread like this:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData * data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[usersArray objectAtIndex:i]objectForKey:#"message"]]];
NSString *localImgpath = [directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#",imageName, #"png"]];
[data writeToFile:localImgpath atomically:YES];
});
When my code hits the web service call, the activity indicator does not show up, and the button freezes in the "selected" state. I would like the activity indicator to run while the web service call is made, so that the screen does not look like it's freezing.
Here is my code to start the activity Indicator:
[activityInd startAnimating];
Here is my code to make a web service call:
NSString *urlString = [NSString stringWithFormat:#"http://us.api.invisiblehand.co.uk/v1/products?query=%#&app_id=dad00cb7&app_key=ab386c3e1b99b58b876f237d77b4211a", [[searchedItem.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] stringByReplacingOccurrencesOfString:#"+" withString:#"%2B"]];
NSURL *url = [NSURL URLWithString:urlString];
NSData *data = [NSData dataWithContentsOfURL:url];
NSDictionary *dataDictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
NSArray *itemCallArray = [NSArray arrayWithArray:dataDictionary[#"results"]];
How do I make the Activity Indicator and the Web Service call run on two separate threads?
Don't rewrite your code, just run it in the background.
NSString *urlString = [NSString stringWithFormat:#"http://us.api.invisiblehand.co.uk/v1/products?query=%#&app_id=dad00cb7&app_key=ab386c3e1b99b58b876f237d77b4211a", [[searchedItem.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] stringByReplacingOccurrencesOfString:#"+" withString:#"%2B"]];
[activityInd startAnimating];
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//Background Thread
NSURL *url = [NSURL URLWithString:urlString];
NSData *data = [NSData dataWithContentsOfURL:url];
NSDictionary *dataDictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
NSArray *itemCallArray = [NSArray arrayWithArray:dataDictionary[#"results"]];
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates
[activityInd stopAnimating];
});
});
Are you running web service call on the main thread. You should never run this on the main thread. This would freeze the GUI and the OS will terminate your app.
Run activity indicator on the main thread and run web service call in another by using blocks.
please let me know if you need more details on how to do this.
I am doing the following when I get an image back from the server. But this code is bringing my app to its knees. It freezes up the UI.
Can this be run on a background thread in iOS? Can I use async?
if (![NSString isEmpty:user.avatarURL])
{
NSString *pathToImage = user.avatarURL;
NSURL *url = [NSURL URLWithString:pathToImage];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [[UIImage alloc] initWithData:data];
[[NSUserDefaults standardUserDefaults] setObject:UIImageJPEGRepresentation(image, 1) forKey:kUserImage];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:#"userAvatar.png" ];
NSData* jpegdata = UIImageJPEGRepresentation(image, 1);
[jpegdata writeToFile:path atomically:YES];
}
As #valentin says, you can do everything inside the if() statement in a dispatch_async() call.
Note I suspect what’s probably slowing you down is actually the -dataWithContentsOfURL:, not the UIImageJPEGRepresentation(), so you’ll want to make sure that’s inside your dispatch_async, not outside.
Also, I’m not clear why you’re decompressing the data into an image, then re-compressing it. You’re going to get artifacts doing this, and with most services the avatar image is going to be compressed anyhow.
I’d do the following:
if (user.avatarURL)
dispatch_async(dispatch_get_main_queue(), ^{
NSURL *const imageURL = [NSURL URLWithString:user.avatarURL];
if (!imageURL)
return;
NSData *const imageDdata = [NSData dataWithContentsOfURL:imageURL];
if (!imageDdata.length)
return;
[[NSUserDefaults standardUserDefaults] setObject:imageDdata forKey:kUserImage];
[imageDdata writeToFile:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:#"userAvatar.png"] atomically:YES];
});
The line which is doing most damage is:
NSData *data = [NSData dataWithContentsOfURL:url];
Because it does the download from the network. Nothing in your code updates the UI so it can all be run on a background thread. Just ensure that if you post a notification or subsequently update the UI after the image is saved that you switch back to the main thread.
the following code is working just fine:
NSURL* urlAddressJSonUrl = [NSURL URLWithString:urlString];
dispatch_async(globalQueue,
^{
NSData *imageData = [NSData dataWithContentsOfURL:urlAddressJSonUrl];
[self performSelectorOnMainThread:#selector(setImage:)
withObject:[UIImage imageWithData:imageData] waitUntilDone:NO];
});
since I need to call it from different viewControllers I want place it in a general class that has public global help function (+) so I'm looking for a way to pass the selector and the target as parameters for performSelectorOnMainThread to run with
You implied that you have the target. Why don't you just call it with the target?
NSURL* urlAddressJSonUrl = [NSURL URLWithString:urlString];
dispatch_async(globalQueue, ^{
NSData *imageData = [NSData dataWithContentsOfURL:urlAddressJSonUrl];
[target performSelectorOnMainThread:#selector(setImage:)
withObject:[UIImage imageWithData:imageData]
waitUntilDone:NO];
});
Or better
NSURL* urlAddressJSonUrl = [NSURL URLWithString:urlString];
dispatch_async(globalQueue, ^{
NSData *imageData = [NSData dataWithContentsOfURL:urlAddressJSonUrl];
dispatch_async(dispatch_get_main_queue(), ^{
[target setImage:[UIImage imageWithData:imageData]];
});
});
I am using the following code which is coming up with a warning. The code does display the correct image - but how can I get rid of the warning?
NSString *indexPath = [[NSBundle mainBundle] pathForResource:name ofType:#"png" inDirectory:#"tunes"];
NSURL *url = [NSURL encryptedFileURLWithPath:indexPath];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [[UIImage alloc] initWithData:data];
warning 'NSURL may not respond to +encryptedFileWithPath:'
That is because NSURL does not have a method called `encryptedFileWithPath:'. If you have copied your code from here, you probably didn't read the article carefully enough:
If you are familiar with NSURL and its class methods then you may have
spotted the unfamiliar encryptedFileURLWithPath: method. I have
extended NSURL using a category to add this method as a convenience.