Xcode, UIImage is NIL when i trying to implement Load image asynchronously - xcode

I trying to implement Load image asynchronously.
NSURL *url = [NSURL URLWithString:_posterImg];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * data,
NSError * error) {
if (!error){
UIImage *getImg = [[UIImage alloc] initWithData:data];
// do whatever you want with image
}
}];
But when i put this code, getImg will get warning "Unused Variable". i had check "response", "data" and "error", it all look fine but the getImg is NIL. is that i had write any thing wrong? thanks.

The affected variable is response. Although you use data and error, response is only declared as a parameter but nowhere used in your completion handler!
NSURL *url = [NSURL URLWithString:_posterImg];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * data,
NSError * error) {
NSString *errorMsg = nil;
UIImage *getImg = nil;
if (!error){
getImg = [[UIImage alloc] initWithData:data];
}
else
{
errorMsg = [NSString stringWithFormat:#"Failed to load image. Error Message: %#", [error localizedString]];
}
[self handleImageRequestWithResponse:response image:getImg andErrorMessage:errorMsg];
}];
// Image hasn't load yet here since the request is asynchronously!
//if(getImg != nil && errorMsg == nil)
// NSLog(#"Image is available!");
//else
// NSLog(#"Loading the image asynchronously failed! %#", errorMsg);
// In addition now provide the following method.
- (void) handleImageRequestWithResponse:(NSURLResponse*)response image:(UIImage*)img andErrorMessage:(NSString*)err
{
if(img!= nil && err == nil)
NSLog(#"Image is available!");
else
NSLog(#"Loading the image asynchronously failed! %#", err);
// Handle image
};
EDIT: My bad! Since the code executes asynchronously getImg was of course nil when you checked as before
EDIT:
Using NSData dataWithContentsOfURL is synchronous,i.e. if executed on the main thread your application is blocked.
See this official documentation: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSData_Class/Reference/Reference.html#//apple_ref/occ/clm/NSData/dataWithContentsOfURL:
Most important:
Important: Do not use this synchronous method to request network-based URLs. For network-based URLs, this method can block the current thread for tens of seconds on a slow network, resulting in a poor user experience, and in iOS, may cause your app to be terminated.
Going for a completionHandler and a handler method called after the requested raw data has been handled/prepared is better for your performance and does not violate the official recommendation!

Related

NSURLSession request HTTPBody becomes nil in Custom NSURLProtocol

In my application, I am performing POST using NSURLSession.
Steps followed:
Setting Header
Setting HTTPBody
Making POST request using NSURLSession.
The code is:
NSDictionary *parameters = #{ #"searchTerm": #"shampoo", #"sort": #"Most Reviewed" };
NSError *error = nil;
NSData *postData = [NSJSONSerialization dataWithJSONObject:parameters options:NSJSONWritingPrettyPrinted error:&error];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"SomeURL"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
[request setHTTPMethod:#"POST"];
[request setAllHTTPHeaderFields:headers];
request.HTTPBody = postData;
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(#"%#", error);
} else {
NSLog(#"Pass");
}
}];
[dataTask resume];
Now in custom NSURLProtocol class:
(BOOL)canInitWithRequest:(NSURLRequest *)request {
if ([request.HTTPMethod isEqualToString:#"POST"]) {
//here request.HTTPMethod is coming nil
//Whereas my requirement is to get request.HTTPMethod which got request parameter.
return YES;
}
return NO;
}
Thanks in advance.
IIRC, body data objects get transparently converted into streaming-style bodies by the URL loading system before they reach you. If you need to read the data:
Open the HTTPBodyStream object
Read the body data from it
There is one caveat: the stream may not be rewindable, so don't pass that request object on to any other code that would need to access the body afterwards. Unfortunately, there is no mechanism for requesting a new body stream, either (see the README file from the CustomHTTPProtocol sample code project on Apple's website for other limitations).

Set NSData dataWithContentsOfURL timeout

So i have this method in my app that returns BOOL if and update is available for my apps content
- (BOOL)isUpdateAvailable{
NSData *dataResponse=[NSData dataWithContentsOfURL:[NSURL URLWithString:#"url that returns json object"] ];
if(dataResponse!=nil){
NSError *error;
dicUpdates = [NSJSONSerialization JSONObjectWithData:dataResponse options:NSJSONReadingMutableContainers error:&error];
}
if(dicUpdates.count > 0) isUpdateAvailable = YES;
else isUpdateAvailable = NO;
return isUpdateAvailable;
}
I need a synchronous request for this, cause the next view controller will be dependent on the server response. However sometimes it takes a long time for the server to respond or the internet is really slow, i need to set a time out to prevent the app from 'being frozen'.
I previously used NSUrlconnection to accomplish this task, but it has been deprecated.
Also, I tried using NSURLSession, (been using it also to download updates in the background thread), but i just can figure out if it can be used for a synchronous request.
Any idea how to deal with this? i just need a synchronous method that returns a BOOL. Best regards.
We have to use NSURLRequest in NSURLSession to set timeout interval.
Check below code:
- (BOOL)isUpdateAvailable{
NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"url that returns json object"] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:4]//timeout
completionHandler:^(NSData *dataResponse,
NSURLResponse *response,
NSError *error) {
// handle response
if(dataResponse!=nil){
NSError *error;
dicUpdates = [NSJSONSerialization JSONObjectWithData:dataResponse options:NSJSONReadingMutableContainers error:&error];
}
if(dicUpdates.count > 0) isUpdateAvailable = YES;
else isUpdateAvailable = NO;
return isUpdateAvailable;
}] resume];
}

Unsupported URL on ios 8

I'm trying to fetch a json from google places with the following code:
NSString *query = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/search/json?location=%f,%f&radius=%i&types=%#&sensor=true&key=%#", center.latitude, center.longitude, rad, types, kGOOGLE_API_KEY];
NSLog(#"%#",query);
NSURL *googleRequestURL=[NSURL URLWithString:query];
[NSURLConnection sendAsynchronousRequest:[[NSURLRequest alloc] initWithURL:googleRequestURL] queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error) {
NSLog(#"Error fetching data: %#",[error description]);
} else {
//To-do
}
}];
The resulting url is: https://maps.googleapis.com/maps/api/place/search/json?location=37.337566,-122.041202&radius=1000&types=accounting|bowling_alley|doctor&sensor=true&key=MY_KEY
(my key is ommitted for obsious reasons)
Which works fine from my laptop's browser, but return the error:
Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo=0x7fe47bc138f0 {NSLocalizedDescription=unsupported URL, NSUnderlyingError=0x7fe47be9dbe0 "unsupported URL"}
I tried using http instead of https (in the browser it returns a json with some error message, but still returns something) with no success.
What am I doing wrong?
This is how I got it resolved. Good Luck!
NSString *google = #"https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=%f,%f&radius=500&types=%#&key=%#";
NSString *link = [NSString stringWithFormat:google, coordinate.latitude, coordinate.longitude, types, GOOGLE_KEY];
NSURL *url = [NSURL URLWithString:[link stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:url];

TWRequest code works but very slow to show?

I'm working with TWrequest to display my twitter lists in a tableview. The following code works. The problem is it is very slow to update the table. I am NSlogging the request response (which happens very quickly), I am also looping through each list and adding the list 'name' to an array (which again, happens very quickly <1s). But for some inexplicable reason, the table takes roughly a further 4 seconds or so to update.
Why is this taking so long for the table to reload? The problem is not parsing the response (because I can see with nslog this happens pretty quick), it's taking a long time to display in the table? Help very much appreciated!
-(IBAction)getLists{
// First, we need to obtain the account instance for the user's Twitter account
ACAccountStore *store = [[ACAccountStore alloc] init];
ACAccountType *twitterAccountType = [store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
// Request permission from the user to access the available Twitter accounts
[store requestAccessToAccountsWithType:twitterAccountType withCompletionHandler:^(BOOL granted, NSError *error) {
if (!granted) {
// The user rejected your request
NSLog(#"User rejected access to the account.");
}
else {
// Grab the available accounts
twitterAccounts = [store accountsWithAccountType:twitterAccountType];
if ([twitterAccounts count] > 0) {
// Use the first account for simplicity
ACAccount *account = [twitterAccounts objectAtIndex:0];
// Now make an authenticated request to our endpoint
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
//[params setObject:#"1" forKey:#"include_entities"];
// The endpoint that we wish to call
NSURL *url = [NSURL URLWithString:#"http://api.twitter.com/1.1/lists/list.json"];
// Build the request with our parameter
TWRequest *request = [[TWRequest alloc] initWithURL:url parameters:params requestMethod:TWRequestMethodGET];
// Attach the account object to this request
[request setAccount:account];
[request performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
if (!responseData) {
// inspect the contents of error
NSLog(#"error = %#", error);
}
else {
NSError *jsonError;
NSArray *timeline = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableLeaves error:&jsonError];
if (timeline) {
// at this point, we have an object that we can parse
NSLog(#"timeline = %#", timeline);
for (NSDictionary *element in timeline) {
NSString *listName = [element valueForKey:#"name"];
[listsArray addObject:listName];
}
[listsTable reloadData];
}
else {
// inspect the contents of jsonError
NSLog(#"jsonerror = %#", jsonError);
}
}
}];
}
}
}];
}
Sorry, just came across this post. If you haven't found a solution yet, hopefully this will help.
I believe that performRequestWithHandler can be called on any thread, so UI changes should be dispatched to the main thread.
dispatch_async(dispatch_get_main_queue(), ^{
//update UI here
});
Or in the case of reloading table data you can use:
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];

Unable to get image from url using NSURLConnection sendSynchronousRequest

I have a special URL that returns an image in a browser. I'd like to put this special image into a UIImage object. However, in my code sample below, it seems that the data returned is not an image.
The browser seems to know about the image, how can I get to the image?
Yes, I need get this image via the proxify proxy server to solve an issue we have.
Here is the sample code.
-(UIImage*)retrieveMap
{
NSString* proxifiedGoogleMapURL = #"http://proxify.com/p/011010A1000100/687474703a2f2f6d6170732e676f6f676c652e636f6d2f6d6170732f6170692f7374617469636d61703f63656e7465723d34312e3031343130312c2d3130342e393738333333267a6f6f6d3d362673697a653d35303678353036267363616c653d32266d6170747970653d726f61647326666f726d61743d706e672673656e736f723d66616c7365";
NSURLRequest * firstRequest = [NSURLRequest requestWithURL:[NSURL URLWithString: proxifiedGoogleMapURL]];
NSURLResponse * firstResponse = nil;
NSError * firstError = nil;
NSData* firstData = [NSURLConnection sendSynchronousRequest:firstRequest returningResponse:&firstResponse error:&firstError];
UIImage* dataAsImage = [UIImage imageWithData:firstData];
if(firstError != nil || dataAsImage == nil)
{
NSLog(#"Failed in retrieving the map");
}
else
{
NSLog(#"Succeeded in retrieving the map");
}
return dataAsImage;
}
I've spotted a few problems:
You should test firstError != nil before you try to convert to an UIImage. Testing it after kind of makes it useless.
I've tried to access that URL you posted and I got an error saying it is available only to users logged in. In the browser it might work for you since you are probably logged in, but the iphone is not and you get that HTML from proxify
To see the response you get, before creating the image convert it to NSString and display it to the console:
NSLog(#"Response from server: %#", [[NSString alloc] initWithData:firstData encoding:NSUTF8StringEncoding]

Resources