+[NSURL URLWithString:] returning nil - ios

I use this code to load a UIImage from a URL:
NSURL *imageURL = [NSURL URLWithString:#"http://testwebsite.com/image.png"];
NSData *imageData = [[NSData alloc] initWithContentsOfURL:imageURL];
imageView.image = [UIImage imageWithData: imageData];
but I'm stuck at a URL that looks like this one :
http://www.testwebsite.com/getFile?userID=123
this works fine in the browser but returns nil in the imageData variable above.
how can I load the image from such an obscured URL (i.e. from a URL that does not show off the file name but rather redirects to the image file) ?
thank you in advance.

for some weird reason I have to use :
[NSURL URLWithString:[urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
when I create the URL and this solved the issue.

NSData initWithContentsOfURL: returns nil if the data cannot be loaded (i.e. if you get a HTTP error code).
Chances are the URL you point to has some referrer blocker or cookie requirement that prevents its use from within your app (just one suggestion of the problem).
I recommend you look at using the following variant instead:
- (id)initWithContentsOfURL:(NSURL *)aURL options:(NSDataReadingOptions)mask error:(NSError **)errorPtr
And pay attention to the value of errorPtr in case the return value is nil.
For example:
NSError *error;
NSData* imageData = [[NSData alloc] initWithContentsOfURL:
[NSURL URLWithString:#"http://example.com/notfound"]
options:0 error:&error];
if(imageData == nil) {
NSLog(#"Error: %#", error);
} else {
NSLog(#"Got %u bytes", imageData.length);
}
You can see the following error:
Error: Error Domain=NSCocoaErrorDomain Code=256 "The operation couldn’t be completed. (Cocoa error 256.)" UserInfo=0xa881c20 {NSURL=http://example.com/notfound}

If you load the image like that it's blocking the main thread and leaving your application unresponsive and I'm not sure if the initWithContentsOfURL: method is handling redirects at all if that is the issue... You can create another class (ImageFetcher for example) that uses NSURLConnection and implements the NSURLConnectionDataDelegate. Using the connection:willSendRequest:redirectResponse: method from the NSURLConnectionDataDelegate you can handle redirects and in the connection:didReceiveData: method you can append the received data to a NSMutableData (it's not guaranteed that you receive all the data in one go). Furthermore you don't have to wait for the connection to finish or download any data if you implement the connection:didReceiveResponse: method and check if the response is indicating an error and in the connectionDidFinishLoading: method you can call another method to update your image view (or call the delegate of the ImageFetcher class with the appropriate data to update the image view).

NSURL URLWithString:#"" will return nil if the URL does not conform to RFC 2396 and they must be escaped
If you read through rfc2396 in the link you will get loads of details
A great site I found for checking where the offending character is, choose the path option for URL
http://www.websitedev.de/temp/rfc2396-check.html.gz

Related

NSData returns <>

I am converting url data into UIImage. This is my code.
NSURL *url = [NSURL URLWithString:strImgURL];
NSData *data = [NSData dataWithContentsOfURL:url options:NSDataReadingUncached error:&error];
NSLog(#"Image Error-------%#",[error localizedDescription]);
imgProf = [[UIImage alloc] initWithData:data];
but My data always returns <>
(lldb) po data
<>
But when I type this url in browser I can get the image. What is the reason for this?
Please help me. Thanks
You're getting an empty response because your code (app) can't authenticate with the server by the sounds of it. This should generally be returned as an error but it depends on the response from the server.
You need to deal with the authentication first, so the app has an auth token or cookie or something and then you can make your request (potentially supplying the auth details in headers).

Ios Intercept UIWebview request via NSURLCache and replace the response

I'm developing an Epub Reader for Ios, notice that i don't use any epub library and i parse the epub myself.
I needed a method for loading resource from epub into the UIWebView, for example images or CSS file ... (resource that requested in the html files).
for this purpose i decided to use NSURLCache class and override it's method (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request
so i can intercept the request and find the right data from epub then create a NSCachedURLResponse and return it.
so far so good. BUT the the problem is that the data (i.e images) wont show in the webview. look at below code:
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request
{
/*
the request.URL is something like this applewebdata://UUID/OEBPS/Images/cover.jpg ,
so the getResourcePathFromRequest give me the path OEBPS/Images/cover.jpg,
so i can find the right data in epub
*/
NSString *resourcePath = [self getResourcePathFromRequest:request.URL];
/*
ResourceResponse is a class contaning data and mimeType,
i tested this and the data and mimeType are good so this is not the problem
*/
ResourceResponse *response = [[self getBook] fetch:resourcePath];
NSURLResponse *urlResponse = [[NSURLResponse alloc] initWithURL:[request URL] MIMEType:response.mMimeType expectedContentLength:[response.mData length] textEncodingName:#"UTF-8"];
NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:urlResponse data:response.mData];
return cachedResponse;
}
at this point everything looks normal, the method getting called, the right data being found and the response object return, but it wont load the image into the webview.
so what is the problem?
tnx in advance.
NOTE: i'm new in ios programming world (coming from android:)
I loaded the data with base url (http://localhost) and everything went fine.

NSData dataWithContentsOfUrl: loads outdated data

In my app I load some static JSON string from some server.
Every now and then the JSON file is updated and then I want the app to reload the data.
Now, that I updated the file on the server the app does not reflect the change. If I take the URL to that file from the app's code and copy it into a browser and fetch the file there, I clearly see the updates. But when I run the app and log the json string to the debug console, then I clearly see an outdated version of the file's content.
Is there any caching involved? Can I force the iOS to actually reload it?
This is how I load it now:
NSURL * url = [NSURL URLWithString:[DOWNLOAD_URL stringByAppendingString:DOWNLOAD_FILE]];
NSError * error;
NSData *jsonData = [NSData dataWithContentsOfURL:url options:NSDataReadingUncached error:&error];
NSLog(#"JSON: %#", [NSString stringWithUTF8String:[jsonData bytes]]);
The option NSDataReadingUncached should prevent the system from caching the data.
PS: When I run the app on a different device, then it receives the current data. But when I again let it run on the original device - on which I observe this behaviour - then the data "received" is still outdated. So it really looks like some cashing issue to me.
Here is an idea. Try calling
[[NSURLCache sharedURLCache] removeAllCachedResponses];
For more granular control on cashing use NSURLConnection or NSURLSession.
I did try Mundi's suggestion, to try clearing the cache, but this didn't make any difference in my iPhone app.
So, I tried a trick which I use in my Angular webapps, and appended the current time (in ticks) to the URL I'm attempting to open, and that did work:
NSString* originalURL = #"http://somewebservices/data/1234";
NSString* newURL = [NSString stringWithFormat:#"%#?t=%f", originalURL,
[[NSDate date] timeIntervalSince1970]];
NSLog(#"Loading data from: '%#'", newURL);
NSURL *url = [NSURL URLWithString:newURL];
if (url == nil)
return false;
NSError *error;
NSData* urlData = [NSData dataWithContentsOfURL:url options:NSDataReadingUncached error:&error];
(Sigh.)
I'm getting too old for this stuff....

NSMutableURLRequest and JSON - How would I finish this connection?

I am trying to fetch data from an api and I have this code:
// create the URL we'd like to query
NSString *urlString = [NSString stringWithFormat:#"https://www.googleapis.com/adsense/v1.1/reports"];
NSString *token = auth.accessToken;
NSMutableURLRequest *myURL = [NSURL URLWithString:urlString];
[myURL addValue:token forHTTPHeaderField:#"Authentication"];
// we'll receive raw data so we'll create an NSData Object with it
######
How would I complete this step? So far I have
NSData *myData =
######
// now we'll parse our data using NSJSONSerialization
id myJSON = [NSJSONSerialization JSONObjectWithData:myData options:NSJSONReadingMutableContainers error:nil];
// typecast an array and list its contents
NSArray *jsonArray = (NSArray *)myJSON;
NSLog(#"%#", jsonArray);
How would I connect on the 9th line?
It looks like you are putting all this code in one place (making a synchronous network request). This is typically a bad idea. You should put the first part (creating and starting the request) in one place, and put the parsing code in a separate method / block that gets called once the request is completed. (This is called an asynchronous network request.)
You should take a look at +[NSURLConnection sendAsynchronousRequest:queue:completionHandler:]. You can pass your NSURLRequest in here, and then specify the completion (parsing, etc.) in the completion handler. It will give you the NSData object you're looking for - see documentation here.
If you have more than a handful of network connections, this can get unwieldy. You may want to look at a third party library like AFNetworking, which can manage much of the tedious stuff for you, and let you focus on calling a URL, and parsing the response.
You need:
NSData *myData = [NSURLConnection sendSynchronousRequest:myURL returningResponse:nil error:nil];
This is a synchronous call. I'll suggest always using asynchronous webcalls is a good way.

ios awkard image loading (url to nsdata to uiimage to uiimageview)

I need you to humor me during this question. This is somewhat pseudo code because the actual situation is quite complex. I wouldn't load an image this way unless I needed to. Assume that I need to.
NSURL *bgImageURL = [NSURL URLWithString:#"https://www.google.com/images/srpr/logo3w.png"];
UIImage *img = [UIImage imageWithData:[NSData dataWithContentsOfURL:bgImageURL]];
[self.anIBOutletOfUIImageView setImage:img];
but I crash out with
-[__NSCFData _isResizable]: unrecognized selector sent to instance 0x9508c70
How can I load an image from a URL into NSData and then load that NSData into a UIImage and set that UIImage as the image for my UIImageView?
Again, I realize this sounds like nonsense, but due to an image caching system I'm using I have to do things this way :(
How I usually handle this situation (not compiled, not tested):
NSURL * url = [NSURL URLWithString:#"https://www.google.com/images/srpr/logo3w.png"];
NSURLRequest * request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue currentQueue]
completionHandler:^(NSURLResponse * resp, NSData * data, NSError * error) {
// No error handling - check `error` if you want to
UIImage * img = [UIImage imageWithData:data];
[self.imageView performSelectorOnMainThread:#selector(setImage:) withObject:img waitUntilDone:YES];
}];
This avoids the long-running network request implied by the call to dataWithContentsOfURL:, so your app can continue doing things on the main thread while the data downloads for the image.
As a side note, you seem to be running into the same error as this question; you might want to check that you're not running into object allocation problems.
I plugged this code into a new, iPad "Single view application" template:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSURL *bgImageURL = [NSURL URLWithString:#"https://www.google.com/images/srpr/logo3w.png"];
NSData *bgImageData = [NSData dataWithContentsOfURL:bgImageURL];
UIImage *img = [UIImage imageWithData:bgImageData];
[[self Imageview] setImage:img];
}
I got the image to load up properly. I even tried different content modes for the UIImageView, and they all worked as expected.
If you start from scratch, do you get the same problem?
The error message indicates that you're sending a message of "_isResizable" to an NSData object. Maybe you're inadvertently setting the UIImageView's image property equal to the NSData instead of the UIImage.
Edit/Update
I even went back and tried different versions of "one-lining" the code to see if any of that mattered, since my "working" copy was slightly altered from your non-working copy. I couldn't get the code to break. My guess would be that the code in question isn't broken, but something nearby is...

Resources