48

I am trying to download the image from the url http://a3.twimg.com/profile_images/414797877/05052008321_bigger.jpg

I am using the following code, but image is not saved in the device. I want to know what I am doing wrong.

 NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://a3.twimg.com/profile_images/414797877/05052008321_bigger.jpg"]];
 [NSURLConnection connectionWithRequest:request delegate:self];

 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
 NSString *documentsDirectory = [paths objectAtIndex:0];
 NSString *localFilePath = [documentsDirectory stringByAppendingPathComponent:@"pkm.jpg"];
 NSData *thedata = NULL;
 [thedata writeToFile:localFilePath atomically:YES];

 UIImage *img = [[UIImage alloc] initWithData:thedata];
User97693321
  • 3,336
  • 7
  • 45
  • 69

9 Answers9

101

I happen to have exactly what you are looking for.

Get Image From URL

-(UIImage *) getImageFromURL:(NSString *)fileURL {
    UIImage * result;

    NSData * data = [NSData dataWithContentsOfURL:[NSURL URLWithString:fileURL]];
    result = [UIImage imageWithData:data];

    return result;
}

Save Image

-(void) saveImage:(UIImage *)image withFileName:(NSString *)imageName ofType:(NSString *)extension inDirectory:(NSString *)directoryPath {
    if ([[extension lowercaseString] isEqualToString:@"png"]) {
        [UIImagePNGRepresentation(image) writeToFile:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", imageName, @"png"]] options:NSAtomicWrite error:nil];
    } else if ([[extension lowercaseString] isEqualToString:@"jpg"] || [[extension lowercaseString] isEqualToString:@"jpeg"]) {
        [UIImageJPEGRepresentation(image, 1.0) writeToFile:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", imageName, @"jpg"]] options:NSAtomicWrite error:nil];
    } else {
        NSLog(@"Image Save Failed\nExtension: (%@) is not recognized, use (PNG/JPG)", extension);
    }
}

Load Image

-(UIImage *) loadImage:(NSString *)fileName ofType:(NSString *)extension inDirectory:(NSString *)directoryPath {
    UIImage * result = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/%@.%@", directoryPath, fileName, extension]];

    return result;
}

How-To

//Definitions
NSString * documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];

//Get Image From URL
UIImage * imageFromURL = [self getImageFromURL:@"http://www.yourdomain.com/yourImage.png"];

//Save Image to Directory
[self saveImage:imageFromURL withFileName:@"My Image" ofType:@"png" inDirectory:documentsDirectoryPath];

//Load Image From Directory
UIImage * imageFromWeb = [self loadImage:@"My Image" ofType:@"png" inDirectory:documentsDirectoryPath];
meda
  • 45,103
  • 14
  • 92
  • 122
Fernando Cervantes
  • 2,962
  • 2
  • 23
  • 34
  • 9
    If you are downloading an image with the expectation of saving it locally and not just displaying it, it would probably be better to create the file using [data writeToFile:options:error:] right away, instead of saving it in a UIImage object first. That way you will avoid re-compressing the image and losing all of EXIF data in the process. – SaltyNuts Nov 21 '12 at 08:02
  • 2
    If you like my code, feel free to download my open source project Atom, which includes the above methods and many more. (https://github.com/fer94/atom) – Fernando Cervantes Jan 11 '14 at 01:48
  • Do not use getImageFromURL for downloading large images as It may block the main thread, causing unresponsive UI. Use an alternative which downloads the image on a background thread. More on https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html – m177312 Aug 07 '15 at 12:22
  • This does exactly what I want. If you want to download image and save it locally, this worth a try. – Trung Bui Jan 18 '16 at 04:14
36

If you set theData to nil, what do you expect it to write to the disk?

What you can use is NSData* theData = [NSData dataWithContentsOfURL:yourURLHere]; to load the data from the disk and then save it using writeToFile:atomically:. If you need more control over the loading process or have it in background, look at the documentation of NSURLConnection and the associated guide.

Alfonso
  • 8,386
  • 1
  • 43
  • 63
8

This is the code to download the image from url and save that image in the device and this is the reference link.

 NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://a3.twimg.com/profile_images/414797877/05052008321_bigger.jpg"]];
 [NSURLConnection connectionWithRequest:request delegate:self];

 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
 NSString *documentsDirectory = [paths objectAtIndex:0];
 NSString *localFilePath = [documentsDirectory stringByAppendingPathComponent:@"pkm.jpg"];
 NSData *thedata = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://a3.twimg.com/profile_images/414797877/05052008321_bigger.jpg"]];
 [thedata writeToFile:localFilePath atomically:YES];
User97693321
  • 3,336
  • 7
  • 45
  • 69
  • Why are you doing an asynchronous call with NSURLConnection and then following it up with a synchronous call to [NSData dataWithContentsOfURL...]? The NSURLConnection portion is just left hanging, doing nothing - but it will still pull data from the network, discarding it afterwards. – SaltyNuts Nov 21 '12 at 08:05
  • @user97693321. How can I add multiple images parsed from web service? – Gajendra K Chauhan Nov 22 '13 at 10:55
4

Get Image From URL

-(UIImage *) getImageFromURL:(NSString *)fileURL {
    UIImage * result;

    NSData * data = [NSData dataWithContentsOfURL:[NSURL URLWithString:fileURL]];
    result = [UIImage imageWithData:data];

    return result;
}

This worked great for me but I ran into memory issues with CFData (store). Fixed it with an autoreleasepool:

 -(UIImage *) getImageFromURL:(NSString *)fileURL {
    @autoreleasepool {
     UIImage * result;

     NSData * data = [NSData dataWithContentsOfURL:[NSURL URLWithString:fileURL]];
     result = [UIImage imageWithData:data];

     return result;
    }
 }
mark.ed
  • 321
  • 2
  • 5
2

Since we are on IOS6 now, you no longer need to write images to disk neccessarily.
Since iOS5 you are now able to set "allow external storage" on an coredata binary attribute. According to apples release notes it means the following:

Small data values like image thumbnails may be efficiently stored in a database, but laarge photos or other media are best handled directly by the file system. You can now specify that the value of a managed object attribute may be stored as an external record - see setAllowsExternalBinaryDataStorage: When enabled, Core Data heuristically decides on a per-value basis if it should save the data directly in the database or store a URI to a separate file which it manages for you. You cannot query based on the contents of a binary data property if you use this option.

Alexander
  • 7,178
  • 8
  • 45
  • 75
2

Hi It is clear that you are writing NULL data to your file.

In your code statement NSData *thedata = NULL; indicates that you assign NULL value to your data.

You are writing NULL data to your file as well.

Please check your code once again.

Joseph at SwiftOtter
  • 4,276
  • 5
  • 37
  • 55
Jim
  • 4,639
  • 5
  • 27
  • 31
  • Note that sending a selector to nil does not have any effect, so actually nothing is written to disk (not even null data). Does not really matter in this case, but just to point out the subtle difference. – Alfonso Mar 23 '10 at 10:59
2
-(IBAction)BtnDwn:(id)sender
{
  [self.actvityIndicator startAnimating];

  NSURL *URL = [NSURL URLWithString:self.dataaArray];
  NSURLRequest *request = [NSURLRequest requestWithURL:URL];
  NSURLSession *session = [NSURLSession sharedSession];

  NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error)
   {

      NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
      NSURL *documentsDirectoryURL = [NSURL fileURLWithPath:documentsPath];
      NSURL *documentURL = [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
      BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:[documentURL path]];

      if (exists)
      {
         NSLog(@"not created");
         UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Download"
                                                    message:@"sory,file already exists"
                                                   delegate:nil
                                          cancelButtonTitle:@"cancel"
                                          otherButtonTitles:nil];
         [alert show];
      }
      else
      { 
         [[NSFileManager defaultManager] moveItemAtURL:location toURL:documentURL error:nil];
         UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Download"
                                                    message:@"Succesfully downloaded"
                                                   delegate:nil
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];
         [self.actvityIndicator stopAnimating];
         NSLog(@"wait downloading......");
         [alert show];
     }
  }];

    [downloadTask resume];    
}
Rahul Mane
  • 1,005
  • 18
  • 33
2

Here is how you can save an image asynchronously in Swift:

requestImage("http://www.asdf.com/89asdf.gif") { (image) -> Void in
    let myImage = image
}

func requestImage(url: String, success: (UIImage?) -> Void) {
    requestURL(url, success: { (data) -> Void in
        if let d = data {
            success(UIImage(data: d))
        }
    })
}

func requestURL(url: String, success: (NSData?) -> Void, error: ((NSError) -> Void)? = nil) {
    NSURLConnection.sendAsynchronousRequest(
        NSURLRequest(URL: NSURL (string: url)!),
        queue: NSOperationQueue.mainQueue(),
        completionHandler: { response, data, err in
            if let e = err {
                error?(e)
            } else {
                success(data)
            }
    })
}

Its included as a standard function in my repo:

https://github.com/goktugyil/EZSwiftExtensions

Esqarrouth
  • 38,543
  • 21
  • 161
  • 168
0

Here's an example of how I download banners to my app. I download the images in the background, and most of my apps do not use reference counting so I release objects.

- (void)viewDidLoad {
    [super viewDidLoad];

    [NSThread detachNewThreadSelector:@selector(loadImageInBackground) toTarget:self withObject:nil];

}

- (void) loadImageInBackground {
    NSURL *url = [[NSURL alloc] initWithString:@"http://yourImagePath.png"];
    NSData *data = [[NSData alloc] initWithContentsOfURL:url];
    [url release];
    UIImage *result = [[UIImage alloc] initWithData:data];
    [data release];

    UIImageView *banner_ImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
    [self.view addSubview:banner_ImageView];
    banner_ImageView.image = result;
    [result release];
}
Bobby
  • 6,115
  • 4
  • 35
  • 36