0

So This code was working for me before iOS 8, I have tested it on 3000 Images download loop in iOS 7.1.

But recently some of my App user Compliant me about App Crash While Image Download Process.

Using this way now Just 200 Images are downloading and App Crashes.

I just figured Out On every Image download There is about 0.6 to 0.8 MB Memory is increasing and after about 200 Images App Crashes.

I have to Download Images Synchronously, Because when i try to download in Background Thread or Asynchronous mode or even try to Use dispatch_async(dispatch_get_main_queue() way. The Process Start after some seconds and till then the While loop i am using just reach to its end.

So Please help me on this issue. What should i do to resolve it.

My code for download Images is:

-(void) downloadImages
{
NSString *myDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
database = [dBName UTF8String];
if (sqlite3_open(database, &dbConnection) == SQLITE_OK)
{
    sqliteQuery = [NSString stringWithFormat: @"SELECT ProductID FROM ProductDetails WHERE ImageDownloadStatus = 0"];
    int i = 0;
    if (sqlite3_prepare_v2(dbConnection, [sqliteQuery UTF8String], -1, &sQLStatement, NULL) == SQLITE_OK)
    {
        while (sqlite3_step(sQLStatement) == SQLITE_ROW)
        {
            @autoreleasepool
            {
                temp = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(sQLStatement, 0)];
                NSString *imageURL = [NSString stringWithFormat:@"http://xxxxxxxxxxxxxxx.jpg",clientSite,temp];

                myImage = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageURL]]];

                NSString *imagePath = [NSString stringWithFormat:@"%@/%@.jpg",myDirectory,temp];
                NSData *imageData = [NSData dataWithData:UIImageJPEGRepresentation(myImage, 1.0f)];
                [imageData writeToFile:imagePath atomically:YES];

                sqliteQuery2 = [NSString stringWithFormat: @"UPDATE ProductDetails SET ImageDownloadStatus = 1 WHERE ProductID = \'%@\'",temp];
                 if (sqlite3_prepare_v2(dbConnection, [sqliteQuery2 UTF8String], -1, &sQLStatement2, NULL) == SQLITE_OK)
                 {
                     if (sqlite3_step(sQLStatement2) == SQLITE_DONE)
                      sqlite3_finalize(sQLStatement2);
                 }

                [self performSelectorInBackground:@selector(updateUILabels) withObject:nil];
                 i = i + 1;   
            }
        }
        sqlite3_finalize(sQLStatement);
    }
    sqlite3_close(dbConnection);
 }
}

-(void) updateUILabels
{
@autoreleasepool
{
    progressCounter.hidden = NO;
    lblProgressStatus.hidden = NO;
    spinner.hidden = NO;
    [spinner startAnimating];

    lblProgressStatus.text = @"Synchronising Product Images...";
    lblProgressCounter.text = [NSString stringWithFormat:@"%d / %d”, i,total];       
}
}
M Zubair Shamshad
  • 2,741
  • 3
  • 23
  • 45
  • First of all read this about performSelectorInBackground http://stackoverflow.com/questions/19500820/gcd-vs-performselectorinbackground-performselectoronmainthread . Also never update UI Elements from a background thread. – AndreasZ Dec 01 '14 at 12:23
  • @AndreasZ I just Check with this `[self performSelectorOnMainThread:@selector(updateUILabels:) withObject:nil waitUntilDone:NO];` but UI is not updating :( – M Zubair Shamshad Dec 01 '14 at 12:58
  • is dowloadImages running on background thread? If not simply call [self updateUILabels]. But if you are not using a background thread for downloadImages you are going to block the main thread. – AndreasZ Dec 01 '14 at 13:11
  • @AndreasZ `downloadImages` is running on main Thread. how can i block main thread – M Zubair Shamshad Dec 01 '14 at 13:19
  • You should be executing downloadImages on an background thread. I have written in your question that "I have to Download Images Synchronously, Because when i try to download in Background Thread or Asynchronous mode or even try to Use dispatch_async(dispatch_get_main_queue() way. The Process Start after some seconds and till then the While loop i am using just reach to its end." What do you mean when you are saying that the while loop you are using reaches its end? – AndreasZ Dec 01 '14 at 13:31
  • @AndreasZ the while loop which i am using to fech `productID` from `sqliteQuery` is recah about its end if after getting a `productID` run backgroung process to download Image. – M Zubair Shamshad Dec 01 '14 at 13:36
  • @AndreasZ I think my Problem is solved. I just Call `downloadImages` from background Thread. now memory is not increasing as it was before. – M Zubair Shamshad Dec 01 '14 at 13:47
  • but i think there is time limit to run a process in background thread. is it...??? – M Zubair Shamshad Dec 01 '14 at 13:48
  • No I don't think there is. There is a time limit for a task to complete when your app is entering the background (multitasking) which is a completely different thing. – AndreasZ Dec 01 '14 at 13:53
  • @AndreasZ Okay wait a while, let me test it again and then i will inform you. then you may update this as answer. – M Zubair Shamshad Dec 01 '14 at 13:59
  • @AndreasZ `downloadImages` is running on background thread. now `[self updateUILabels];` is not updating the UI. if i just call this method as background too then UI is updating – M Zubair Shamshad Dec 01 '14 at 14:13
  • @AndreasZ Calling `downloadImages` in BackGround Thread and Updating UI as `dispatch_async(dispatch_get_main_queue(), ^{ [self updateUILabels]; }); ` is worked for me ... please update it as answer – M Zubair Shamshad Dec 01 '14 at 14:24

1 Answers1

1

You should execute the downloadImages method in the background and the updatedUILabels method in the main thread. You can use dispatch_async(dispatch_get_main_queue(), ^{ [self updateUILabels]; }); or [self performSelectorOnMainThread:@selector(updateUILabels:) withObject:nil waitUntilDone:NO]; the execute updatedUILabels in the main thread.

In general always execute long running operations in an background thread (either using GCD, NSOperations or blocks) and always execute functions that update your UI on the main thread.

AndreasZ
  • 1,060
  • 13
  • 16