How to tell if the NSData returns nil if theres no internet connection or if the image is no longer available ??
this is the code:
NSString *str = #"http://p.twimg.com/A76-I-PCYAA75YH.jpg";//URL is broken
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
image = [UIImage imageWithData:imgData];
The nsdata is nil in two cases:
If thers no internet connection.
Or if the image in the url is no longer available.
Try this code.
NSURL* url = [NSURL URLWithString:#"http://imageAddress.com"];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * data,
NSError * error) {
if (!error){
NSImage* image = [[NSImage alloc] initWithData:data];
// do whatever you want with image
}
}];
You should first test for an available network data connection separately, see Apple's Reachability sample code.
Then, if you have a network connection, you can go ahead and try and load the file. If it then fails, you know it's not because there was no network data connection.
Before downloading check for internet connection and then download. You can check availaibility bu putting condition of
if(imgdata == nil)
// image is not available in server
else
// convert data into image and use
image = [UIImage imageWithData:imgData];
Related
This is probably a simple fix, but I'm new to this.
NSString *barImageURLString = barDic[#"image_url"];
NSURL *barImageURL = [NSURL URLWithString:barImageURLString];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSData *imageData = [NSData dataWithContentsOfURL:barImageURL];
dispatch_async(dispatch_get_main_queue(), ^{
// Update the UI
cell.barImageView.image = [UIImage imageWithData:imageData];
});
});
NSString *ratingImageURLString = barDic[#"rating_img_url"];
NSURL *ratingImageURL = [NSURL URLWithString:ratingImageURLString];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSData *imageData = [NSData dataWithContentsOfURL:ratingImageURL];
dispatch_async(dispatch_get_main_queue(), ^{
// Update the UI
cell.ratingImage.image = [UIImage imageWithData:imageData];
});
});
Not sure how I would go about that with the dispatch_async in there.
Doing a POST not just a refactor of your code, which has the GET operation buried in dataWithContentsOfURL:. Here's more general POST code...
NSData *data = // init this to the data that you want to post
NSString *someURLString = #"http://www.myservice.com/mypost.php";
NSURL = *url = [NSURL URLWithString:someURLString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = #"POST";
// depends on the data, but something like this to set a header...
[request setValue:#"application/xml; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
request.HTTPBody = data;
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (!error) {
}
}];
This can be refactored into a GET by replacing the mutable url request with an immutable request and optionally adding query parameters to the url string.
Your code works under ideal conditions, but you want to do some error checking to prevent runtime exceptions.
NSString *barImageURLString = barDic[#"image_url"];
NSURL *barImageURL = [NSURL URLWithString:barImageURLString];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSData *imageData = [NSData dataWithContentsOfURL:barImageURL];
// check for valid data
if ( imageData ) {
// create the UIImage first and make sure it is a valid image
UIImage *image = [UIImage imageWithData:imageData];
if ( image ) {
dispatch_async(dispatch_get_main_queue(), ^{
// It is possible that your tableview cell is no longer on screen, check
YourTableViewCell *cellBeingUpdated = (id)[tableView cellForRowAtIndexPath:indexPath];
if ( cellBeingUpdated ) {
// Update the UI
cellBeingUpdated.barImageView.image = image;
}
});
}
}
});
Same applies to your other image. You want to have some sort of default image in case this fails. What I do is have a default image that I assign to the tableview cell before making the image request. This prevents blank imageviews while waiting for the actual image loading.
Since the logic of fetching the image and doing something with it is mostly the same, and you don't want to repeat the code everytime a new kind of image needs to be loaded, you can create a function or method to do the repetitive work. The input to the function will be a URL to an image, and the output will be the image itself. Since the actual fetch will be asynchronous, the function can take in as input a block of code with instructions on what to do once the image is available. The block can also be notified of failures if the image could not be fetched for some reason.
- (void)fetchImageFromURL:(NSURL *)imageURL completionHandler:(void(^)(UIImage *image, NSError *error))completionHandler {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
NSError *error = ...; // do error handling if image load fails
dispatch_async(dispatch_get_main_queue(), completionHandler(imageData, error);
});
}
This can be invoked as:
NSString *barImageURL = [NSURL URLWithString:barDic[#"image_url"]];
[self fetchImageFromURL:barImageURL completionHandler:^(UIImage *image, NSError *error) {
if (error != nil) {
// handle error
}
else {
cell.barImageView.image = image;
}
}];
Although it only seems to be cutting down a few lines of repetitive code, this design allows your code to be more flexible and scalable. This hides the implementation detail of how the image is actually fetched. Maybe you want to replace it with an asynchronous NSURLConnection, or with NSURLSession. This design allows for that kind of modifications without impacting the API. Error handling can be kept in a single place. Network requests can fail for a variety of reasons with the topmost reason being bad or no connectivity. You can add retry logic for such failures within the -fetchImageFromURL: method again without impacting the method API and callers. Maybe there is some caching you've built so there's no need to go out to the network at all. Again, this design would allow for such a growth.
In the most general terms, you want to separate the "what" from the "how". The what here is the image that some part of your code needs but it shouldn't concern itself with how that image is retrieved.
I'm practicing how to parse XML data and store it into the sqlite. I have done parsing and storing successfully. But I have one problem with displaying image from an url. The URL is formed by combining two NSStrings. One for the fixed address(which I set value) and other based on the name of the photo(retrieved from Sqlite). I am able to create complete URL by retrieving name of photo from Sqlite. But strange thing happen when I use that URL to display image in UIImageView. It does not work. After some testing, I found out there is something wrong with the portion(photo name) I retrieved from Sqlite. If I combine the fixed address with literal name of the photo, it works. Can somebody explain why it happens like this. Thanks in advance.
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"user.db"];
FMDatabase * database = [FMDatabase databaseWithPath:defaultDBPath];
[database open];
results=[database executeQuery:#"SELECT * FROM plant WHERE name=?",self.plantname];
while([results next]) {
name = [results stringForColumn:#"name"];
category = [results stringForColumn:#"category"];
instructions = [results stringForColumn:#"instructions"];
price = [results stringForColumn:#"price"];
photo=[results stringForColumn:#"photo"];
}
NSString * fixedURL = #"http://services.hanselandpetal.com/photos/";
NSString *url=[fixedURL stringByAppendingString:photo];
NSLog(url);
NSURL * imgURL = [NSURL URLWithString:url];
NSData * imageData = [NSData dataWithContentsOfURL:imgURL];
UIImage * image = [UIImage imageWithData:imageData];
self.plantImageView.image=image;
Edit
I've edited based on Rob answer. But there are still problems. I put log below. I've already tried to remove white spaces by using [photo stringByReplacingOccurrencesOfString:#" " withString:#""]. But it does not seem to affect.
2014-10-15 02:12:39.505 SqlitePractice[9256:286525] url string = 'http:/services.hanselandpetal.com/photos/mona_lavender.jpg'
2014-10-15 02:12:39.506 SqlitePractice[9256:286525] imgURL = (null)
2014-10-15 02:12:39.516 SqlitePractice[9256:286525] sendAsynchronousRequest failed: Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo=0x7a78ba50 {NSUnderlyingError=0x7a66b5e0 "unsupported URL", NSLocalizedDescription=unsupported URL}
Edit 2
The URL seems to be problem after changing from stringByAppendingString to stringByAppendingPathComponent. But I found out that even without one slash after http: , it works if I change the photo value. And the image is displayed.
NSString * fixedURL = #"http://services.hanselandpetal.com/photos/";
photo=#"bougainvillea.jpg";
NSString *url=[fixedURL stringByAppendingPathComponent:photo];
NSLog(#"url string = '%#'", url);
NSURL * imgURL = [NSURL URLWithString:url];
NSLog(#"imgURL = %#", imgURL);
And the log is below,
2014-10-15 12:07:56.650 SqlitePractice[9690:308022] url string = 'http:/services.hanselandpetal.com/photos/bougainvillea.jpg'
2014-10-15 12:07:56.651 SqlitePractice[9690:308022] imgURL = http:/services.hanselandpetal.com/photos/bougainvillea.jpg
Edit 3
I have changed based on Rob's modified answer.
NSURL *fixedURL = [NSURL URLWithString:#"http://services.hanselandpetal.com/photos/"];
NSURL *url = [fixedURL URLByAppendingPathComponent:[photo stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSLog(#"image URL = '%#'", url);
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error) {
NSLog(#"sendAsynchronousRequest failed: %#", error);
return;
}
UIImage *image = [UIImage imageWithData:data];
self.plantImageView.image=image;
}];
And here is the log message:
2014-10-15 13:40:38.977 SqlitePractice[10436:357359] image URL = 'http://services.hanselandpetal.com/photos/camellia.jpg%250A%2520%2520%2520%2520'
A couple of thoughts:
Unrelated to your problem at hand, instead of stringByAppendingString, it's generally better to use URLByAppendingPathComponent with a NSURL. It takes care of adding any necessary / characters for you. Not critical given your example, but it's more robust.
Also, if the string might have spaces or other characters not permitted in a URL, you might percent escape it, too.
Thus, you'd do something like:
NSURL *fixedURL = [NSURL URLWithString:#"http://services.hanselandpetal.com/photos/"];
NSURL *url = [fixedURL URLByAppendingPathComponent:[photo stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
You should NSLog the NSURL variable and make sure it's not nil (e.g. which could be caused if there were some spaces in the photo string, for example, unless you percent escape it).
In your revised question, in which you share the log, the original URL string (before the conversion to the NSURL) is being reported as:
http:/services.hanselandpetal.com/photos/mona_lavender.jpg
That should be:
http://services.hanselandpetal.com/photos/mona_lavender.jpg
If imgURL is not nil, but imageData is, you might want to retrieve the image data in a manner that retrieves the error. For example, you could:
NSError *error = nil;
NSData *imageData = [NSData dataWithContentsOfURL:imgURL options:0 error:&error];
if (!imageData) {
NSLog(#"dataWithContentsOfURL failed: %#", error);
}
Bottom line, go through this one line at a time and identify precisely where it is going wrong.
As an aside, you generally would want to avoid using dataWithContentsOfURL, but instead use an asynchronous method:
NSURL *fixedURL = [NSURL URLWithString:#"http://services.hanselandpetal.com/photos/"];
NSURL *url = [fixedURL URLByAppendingPathComponent:[photo stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NRURLRequest *request = [NSURLRequest requestWithURL:imgURL];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error) {
NSLog(#"sendAsynchronousRequest failed: %#", error);
return;
}
UIImage *image = [UIImage imageWithData:data];
self.plantImageView.image=image;
}];
I belive that UIIMAGEVIEW will not display Url as image path. I would sugest to try with UIWebView which would display web content (image or whole web page). This example is writen in objective-c.
self.myWebView = [[UIWebView alloc] initWithFrame:self.view.bounds];
self.myWebView.scalesPageToFit = YES ;
[self.view addSubview:self.myWebView];
NSURL *url = [NSURL URLWithString:#"http://services.hanselandpetal.com/photos/mona_lavender.jpg"];
NSURLRequest *request = [ NSURLRequest requestWithURL:url];
[self.myWebView loadRequest:request]
this is my code to load my images.
NSString *urltest = test[#"images"][#"items"][i][#"url"];
url = [NSURL URLWithString:urltest];
data = [NSData dataWithContentsOfURL:url];
img = [[UIImage alloc] initWithData:data];
[self.imgView setImage:img];
I would like to know when my is loaded. How can i do that?
In XCode Debugger section (located at the bottom left of the XCode), you can check image object value by inserting breakpoint there. You can also preview its value by clicking on preview button (human eye look like button).
You can achive it by,
First write this code
[self performSelectorOnMainThread:#selector(LoadImage:) withObject:#"MY URL STRING" waitUntilDone:NO];
And then
-(void)LoadImage:(NSString *) urlString
{
/// do something when image is loading
NSURL *imgURL=[NSURL URLWithString:urlString];
NSData *imgData=[NSData dataWithContentsOfURL:imgURL];
[self performSelectorInBackground:#selector(setImage:) withObject:imgData];
}
-(void)setImage:(NSData *) imgData;
{
/// do something when image loading is over
myImageView.image=[UIImage imageWithData:imgData];
}
And if you want to know your image is successfully downloaded or not then use following code
[NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:[NSURL URLWithString::#"MY URL STRING"]] queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse* response, NSData* data, NSError* error){
if(error)
{
// Error Downloading image data
}
else
{
[myImageView setImage:[UIImage imageWithData:data]];
}
}];
Hey I'm new to iPhone and I have been trying to display image icons on table view cell in offline mode.
Using NSUserDefault i am storing array objects locally in Online mode. I am using a method that creates a NSURLRequest, and sends that request with the NSURLConnection method sendAsynchronousRequest:queue:completionHandler:. Sometimes I am not getting any response using this method, so completionHandler is not calling. So i am not getting any image icon on table. Does anyone know how to fix this?
here is my code :
QuickLinksTab *quickLinksmenu = [[QuickLinksTab alloc] init];
quickLinksmenu = [arrayLinks objectAtIndex:indexPath.row];
cell.lblName.text = quickLinksmenu.title;
NSString *strQuickLink = [NSString stringWithFormat:#"http://%#",quickLinksmenu.iconImage];
NSURL* url = [NSURL URLWithString:strQuickLink];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * data,
NSError * error) {
if (error)
{
NSLog(#"ERROR CONNECTING DATA FROM SERVER: %#", error.localizedDescription);
}
else{
UIImage* image = [[UIImage alloc] initWithData:data];
// do whatever you want with image
if (image) {
cell.imageIcon.image = image;
}
else{
cell.imageIcon.image = [UIImage imageNamed:#"DefaultPlace.png"];
}
}
}];
QuickLinksTab is my entity class, i am storing quickLinksmenu.title and quickLinksmenu.iconImage locally in my app. I am getting Error message - `
ERROR CONNECTING DATA FROM SERVER:
The Internet connection appears to be offline.
Thanks in Advance.
After login to the salesforce in my app I am making service call which returns the list of products with attributes like productName and product image url.
I am trying to download the image from product image url in this way
SFOAuthCredentials *credentials =[SFAccountManager sharedInstance].credentials;
NSString *urlString = [NSString stringWithFormat:#"%#?oauth_token=%#",imageUrl,credentials.accessToken];
NSURL *imgUrl = [[NSURL alloc] initWithString:[URLString stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
NSURLRequest *imgRequest=[[NSURLRequest alloc]initWithURL:imgUrl];
[NSURLConnection sendAsynchronousRequest:imgRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
UIImage *image=[[UIImage alloc] initWithData:data];
NSLog(#"Image Object %#",image);
}];
I am getting the data object of size around 1820 bytes, but while converting NSData to UIImage by using UIImage classsMethod [UIImage iamgeWithData:data] or instance method [UIImage alloc] initWithData:data] I am getting null
Can anyone help me to fix this issue?.