1

I update my tableview by loading json result from server using NSOperationQueue

Adding queue:

- (void)AddQueue
{
   NSOperationQueue *queue = [NSOperationQueue new];
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
                                                                            selector:@selector(loadDataWithOperation)
                                                                              object:nil];
    [queue addOperation:operation];
} 

Loading result:

-(void)loadDataWithOperation{

    // Create array to hold dictionaries
    myObject = [[NSMutableArray alloc] init];

    NSData *jsonData = [NSData dataWithContentsOfURL:
                        [NSURL URLWithString:@"http://www.test.com/json.php"]];

    if(jsonData != nil)
    {
        NSError *error = nil;
        id jsonObjects = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
        if (error == nil){

            // values in foreach loop
            for (NSDictionary *dataDict in jsonObjects) {
                strPhotoID = [dataDict objectForKey:@"id"];
                strName = [dataDict objectForKey:@"title"];
                strUrl = [dataDict objectForKey:@"url"];
                strThumb = [dataDict objectForKey:@"thumb"];
                strDay = [dataDict objectForKey:@"day"];
                strDate = [dataDict objectForKey:@"date"];
                strLikes = [dataDict objectForKey:@"likes"];
                strDeviceid = [dataDict objectForKey:@"deviceid"];
                strActive = [dataDict objectForKey:@"active"];

                dict = [NSDictionary dictionaryWithObjectsAndKeys:
                        strPhotoID, photoid,
                        strName, title,
                        strThumb, thumb,
                        strUrl, photourl,
                        strDay, day,
                        strDate, date,
                        strLikes, likes,
                        strDeviceid, deviceid,
                        strActive, active,
                        nil];


                [myObject addObject:dict];

                NSSortDescriptor * sortDesc = [[NSSortDescriptor alloc] initWithKey:@"id" ascending:NO];
                [myObject sortUsingDescriptors:[NSArray arrayWithObject:sortDesc]];


                [self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];

                [self performSelectorOnMainThread:@selector(endAnimating) withObject:nil waitUntilDone:YES];


            }
        }

    }


}

This code works well and load what I need, but if I load my result multiple times app crashes. I think it happens because of many operations at same time. How to prevent app crashing?

Log:

libobjc.A.dylib`_cache_getImp:
0x39a39580:  lsr.w  r9, r1, #2
0x39a39584:  ldr    r3, [r0, #8] // EXC_BAD_ACCESS
0x39a39586:  add.w  r3, r3, #8
0x39a3958a:  ldr    r12, [r3, #-8]
0x39a3958e:  and.w  r9, r9, r12
0x39a39592:  ldr.w  r0, [r3, r9, lsl #2]
0x39a39596:  teq.w  r0, #0
0x39a3959a:  add.w  r9, r9, #1
0x39a3959e:  beq    0x39a395b2                ; _cache_getImp + 50
0x39a395a0:  ldr.w  r12, [r0]
0x39a395a4:  teq.w  r1, r12
0x39a395a8:  bne    0x39a3958a                ; _cache_getImp + 10
0x39a395aa:  ldr.w  r12, [r0, #8]
0x39a395ae:  mov    r0, r12
0x39a395b0:  bx     lr
0x39a395b2:  mov.w  r0, #0
0x39a395b6:  bx     lr
0x39a395b8:  nop    
0x39a395ba:  nop    
0x39a395bc:  nop    
0x39a395be:  nop    

Stack trace:

(
    0   testApp                             0x000ddd09 -[Perjantai loadDataWithOperation] + 72
    1   CoreFoundation                      0x31d46ad4 <redacted> + 68
    2   CoreFoundation                      0x31c9e28f <redacted> + 290
    3   Foundation                          0x32647f65 <redacted> + 112
    4   Foundation                          0x325d1a89 <redacted> + 840
    5   Foundation                          0x32649fe7 <redacted> + 102
    6   libdispatch.dylib                   0x39e58793 <redacted> + 10
    7   libdispatch.dylib                   0x39e5c657 <redacted> + 278
    8   libdispatch.dylib                   0x39e5c7d9 <redacted> + 92
    9   libsystem_c.dylib                   0x39e807f1 <redacted> + 360
    10  libsystem_c.dylib                   0x39e80684 start_wqthread + 8
)
Pavel Kaljunen
  • 1,291
  • 2
  • 26
  • 53
  • Show the crash log and stack trace. – Wain Jun 08 '13 at 12:34
  • How frequently is AddQueue method called ? I see you are creating new operation queue for an operation instead of just creating ONE queue in the init method of the class and add operation to that queue. – 0x8badf00d Jun 08 '13 at 12:53
  • this method called if user tap on refresh button... how can I create just one queue? – Pavel Kaljunen Jun 08 '13 at 12:57
  • 2
    I assume `myObject` is an ivar because you do `myObject = [[NSMutableArray alloc] init];` and not `NSMutableArray *myObject = [[NSMutableArray alloc] init];`. I think that could be your problem if `myObject` is not thread-safe. However, if you think that too many concurrent operations are the problem you can set the maximum with `[queue setMaxConcurrentOperationCount:1];` or whatever you like ;) – HAS Jun 08 '13 at 15:49

1 Answers1

3

In your first block of code, you allocate the queue, but don't keep a strong reference to it, so it gets realloced right away. Create an ivar, create one queue early on, and add objects to it as needed. Using ARC the ivar will get released on its own, but in your dealloc you probably want to either wait for all operations to complete, or cancel them then wait - to avoid a different crash.

CODE:

@implementation myClass
{
  NSOperation *q;
}

- (id)init....
...
    q = [NSOperationQueue new];
...
  return self;
}

- (void)dealloc
{
  [q cancelAllOperations];
  [q waitUntilAllOperationsAreFinished];
  ...
}
David H
  • 40,852
  • 12
  • 92
  • 138