M Zubair Shamshad
M Zubair Shamshad

Reputation: 2741

Memory management in iOS , Simulator vs idevice gives different result

i am downloading images from a server, this is my code.

-(void) DownloadImages
{
   NSLog(@"Images count to download %lu",(unsigned long)[productID count]); // about 3000
   if ([productID count] > 0)
   {
       // Document Directory
       NSString *myDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
       for (i = 0; i < [productID count]; i++)
       {
       @autoreleasepool      // is this right of use autoreleasepool???
       {
           @autoreleasepool      
           {
               [self performSelectorInBackground:@selector(UpdateUI) withObject:nil];
           }
           NSLog(@"image no %d", i);
          NSString *imageURL = [NSString stringWithFormat:@"http://serverPath/%@/OnlineSale/images/products/%@img.jpg",clientSite,[productID objectAtIndex:i]];
           UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageURL]]];
           // Reference path
           NSString *imagePath = [NSString stringWithFormat:@"%@/%@img.jpg",myDirectory,[productID objectAtIndex:i]];
          NSData *imageData = [NSData dataWithData:UIImageJPEGRepresentation(image, 1.0f)];
          [imageData writeToFile:imagePath atomically:YES];   
        }
     }
      NSLog(@"Downloading images completed...");
  }

}

EDIT: this is UpdateUI method

 -(void) UpdateUI
 {
    spinner.hidden = NO;
[spinner startAnimating];
    progressCounter.hidden = NO;
    status.text = @"Synchronising Product Images...";
    progressCounter.text = [NSString stringWithFormat:@"%d / %lu", i,(unsigned long)[productID count]];
 }

while processing this, when i am in simulator the maximum memory used is: on more than 1500 images download.

enter image description here

but testing on iPad, the maximum memory is reached to 106.9 MB and app crashed with this message, just after 500 images download:

enter image description here

and screen shows this message: enter image description here

i am stuck on this point from last two days, after scratching my head don't find any solution. please help me on this issue..

Edit: using autoreleasedpool way is right or not???

Upvotes: 0

Views: 155

Answers (2)

sergio
sergio

Reputation: 69027

First of all, I would suggest enclosing the whole for loop block inside of @autoreleasepool. It would look like this:

   for (i = 0; i < [productID count]; i++)
   {
     @autoreleasepool      // is this right of use autoreleasepool???
     {
        [self performSelectorInBackground:@selector(UpdateUI) withObject:nil];
         NSLog(@"image no %d", i);
         NSString *imageURL = [NSString stringWithFormat:@"http://serverPath/%@/OnlineSale/images/products/%@img.jpg",clientSite,[productID objectAtIndex:i]];
         UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageURL]]];
         // Reference path
         NSString *imagePath = [NSString stringWithFormat:@"%@/%@img.jpg",myDirectory,[productID objectAtIndex:i]];
         NSData *imageData = [NSData dataWithData:UIImageJPEGRepresentation(image, 1.0f)];
         [imageData writeToFile:imagePath atomically:YES];   
      }
   }

If what you tried to accomplish with your @autoreleasepool block was handling memory allocated in updateUI, that is not the right approach. You should instead enclose updateUI body inside of @autoreleasepool.

I would also suggest to post the content of updateUI; you could even comment that call out and see whether the download-only is causing the memory issue.

More generally, it seems pretty suspicious to me that you are updating the UI on a background thread. UI should be only updated on the main thread, as a general practice. (But without seeing updateUI definition, I cannot really say if this is ok or not).

About the different results you get with a device or the simulator, this is "normal". The simulator is totally unreliable when it come to memory handling, you could also detect leaks with the simulator that are not there on a device.

EDIT:

As an easy patch, try with this approach:

for (i = 0; i < [productID count]; i++)
   {
      dispatch_async(dispatch_get_main_queue(), ^{

        [self UpdateUI];

         NSLog(@"image no %d", i);
        NSString *imageURL = [NSString stringWithFormat:@"http://serverPath/%@/OnlineSale/images/products/%@img.jpg",clientSite,[productID objectAtIndex:i]];
         UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageURL]]];
         // Reference path
         NSString *imagePath = [NSString stringWithFormat:@"%@/%@img.jpg",myDirectory,[productID objectAtIndex:i]];
        NSData *imageData = [NSData dataWithData:UIImageJPEGRepresentation(image, 1.0f)];
        [imageData writeToFile:imagePath atomically:YES];   
      });
 }

As you'll notice, I am dispatching each step in the loop individually. In this way, the mail loop will be able to update the UI. Notice that this implementation is not optimal, since dataWithContentsOfURL will take a little to execute (since it entails a network access) and should not be executed on the main thread (but you were doing it already like this). That should be dispatched on a background queue.

Upvotes: 2

Skie
Skie

Reputation: 2012

You should use more appropriate method for fetching Image data. I suggest you to try NSURLDownload class.

Alternatively you could use one of popular 3rd party networking framework like AFNetworking

Upvotes: 0

Related Questions