1

I have code that will check to see if an image is on the phone or not (the name being retrieved from the db), and if not, it runs this code:

NSString *urlString = [NSString stringWithFormat: @"http://www.vegashipster.com/%@",image_path];                        
NSData *imageData = [[NSData alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]]];

NSLog(@"saving jpg");
UIImage *image = [[UIImage alloc] initWithData:imageData];//1.0f = 100% quality

[UIImageJPEGRepresentation(image, 1.0f) writeToFile:myFilePath atomically:YES];
NSLog(@"saving image done");
NSLog(@"URL String: %@",urlString);
NSLog(@"http://www.vegashipster.com/%@",image_path);

rest_image = [UIImage imageNamed:image_path];

[image release];
[imageData release];

This code works just fine on the simulator, but on the iPhone, the screen freezes for a few seconds (downloading the image, I think), then loads the page, but with no image visible. The next time you hit that page, there is no freeze. So I believe the file is being created, but it's a messed up image file, and therefore not displayed.

I've already broken this code up so that it runs in it's own thread, and again, it works in the simulator. I had thought that if it ran behind the scenes, there would be less of a chance that the image data would get messed up, but the exact same thing happens (minus the freezing). Does anyone know what I am doing wrong with this code? Thanks for any and all help/comments.

Edit

And yes, the images being downloaded are strictly .jpg

Edit 2

I seen:

Make sure you are writing to your DOCUMENTS directory, which you have read+write access to. Otherwise you won't get any files.

at http://www.iphonedevsdk.com/forum/iphone-sdk-development/15628-file-weirdness-files-written-disk-do-not-appear-nsfilemanager-defaultmanager.html . Could this be my issue?

NSString *image_path = [[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 5)] stringByReplacingOccurrencesOfString:@"../"
NSString *myFilePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:image_path];

Last Edit

Well, I found what I believe to be my answer at How can I get a writable path on the iPhone? . It pretty much states I cannot save image files where my own image files are located inside the build. If this is incorrect, please let me know and I will try your way.

Community
  • 1
  • 1
James
  • 3,765
  • 4
  • 48
  • 79

2 Answers2

1
NSData *imageData = [[NSData alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]]];

Is a synchronous call, ie it blocks until it has fully executed, which in the case of network operations can be 1 second, 10 seconds or 3 minutes if you don't have a time out. You are presumably running this on the main thread which is why your UI freezes (all UI stuff is done on the main thread so you must do everything not to block it). The reason it doesn't freeze the next time around is probably that it has cached the image data.

You should use asynchronous APIs, NSURLConnection has some, however I strongly recommend ASIHTTPRequest, which is an obj c wrapper around NSURLConnection and co. The code would look something like this (read through the how to use section)

- (IBAction)grabURLInBackground:(id)sender
{
   NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"];
   ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
   [request setDelegate:self];
   [request startAsynchronous];
}

- (void)requestFinished:(ASIHTTPRequest *)request
{
   // Use when fetching text data
   NSString *responseString = [request responseString];

   // Use when fetching binary data
   NSData *responseData = [request responseData];
   UIImage* downloadedImage = [UIImage imageWithData:responseData];
}

- (void)requestFailed:(ASIHTTPRequest *)request
{
   NSError *error = [request error];
}
jbat100
  • 16,757
  • 4
  • 45
  • 70
  • Right, I understand why it freezes and such, but I do not understand why the image is not displayed after it is done, as does the simulator. I've already rewritten it so that it's in it's own thread, but I would like to see it solved like this before I implement it into the other thread to make sure it's working. But I appreciate the comment. – James Oct 06 '11 at 20:04
  • I'm not sure but it could be that the UIImage thing should be done on the main thread (as a general rule UI == main thread), sorry I misread didn't realize you were already spawning a background thread. The advantage of the callback techniques is that the download is done in the background but the callbacks are done on the same thread that started it (here, should be the main thread). – jbat100 Oct 06 '11 at 20:09
  • Well even with it all in the main thread, the image is not shown. It's as if the image download failed or the file got corrupted or something similar. But I am not sure what, or why. As I said, this works just fine on the simulator, so I don't know if I am telling it to save wrong or what. – James Oct 06 '11 at 20:22
  • Given the image data you download is already a jpg, what happens if you just save the data you receive straight to a .jpg file on disk? – jbat100 Oct 06 '11 at 20:31
  • I'm not sure. I've actually never saved a file previously, and that was kind of how the example was set up. I will try without and let you know. – James Oct 06 '11 at 20:35
  • It crashes the program when I do that saying I sent an invalid selector. – James Oct 06 '11 at 20:53
0

Sorry, forgot about this thread completely. I did end up fixing this issue. Here is what I did:

NSFileManager* fileManager = [NSFileManager defaultManager];

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *libraryDirectory = [paths objectAtIndex:0];

NSString *myFilePath = [libraryDirectory stringByAppendingPathComponent:image_path];

BOOL fileExists = [fileManager fileExistsAtPath:myFilePath];

if (fileExists){
    hotel_image = [UIImage imageWithContentsOfFile:myFilePath];
}else{
    [NSThread detachNewThreadSelector:@selector(downloadImage:) toTarget:[HotelsDetailsViewController class] withObject:image_path];

    fileExists = [fileManager fileExistsAtPath:myFilePath];

    if (fileExists){
        hotel_image = [UIImage imageWithContentsOfFile:myFilePath];
    }else{
        hotel_image = [UIImage imageNamed:@"hdrHotels.jpg"];
    }
}

In short, I found my app's library directory and saved there.

James
  • 3,765
  • 4
  • 48
  • 79