简体   繁体   中英

Asynchronous loading and UITableView's -reloadData

I currently try to figure out why the following code snippet produces an error. I am using the Google Calendar API to load calendars. However I assume that it's loading its data asynchronously and therefore when I call -reloadData my app crashes without console errors.

[[GDataHandler sharedDataHandler] fetchCalendarsWithCompletion:^(GDataFeedBase *feed) {


     //CRASH !!! Trying to execute code on main thread
     dispatch_async(dispatch_get_main_queue(), ^{

        for(GDataEntryCalendar *cal in feed.entries){

            if([cal isKindOfClass:[GDataEntryCalendar class]]){
                NSLog(@"adding %@", cal.title.stringValue);
                [calendarArray addObject:cal];
            }

        }

        [list reloadData];

    });

}];

Backtrace looks like this:

* thread #1: tid = 0xeabe5, 0x39ed81fc libsystem_kernel.dylib`__pthread_kill + 8, queue = 'com.apple.main-thread, stop reason = signal SIGABRT
    frame #0: 0x39ed81fc libsystem_kernel.dylib`__pthread_kill + 8
    frame #1: 0x39f3fa52 libsystem_pthread.dylib`pthread_kill + 58
    frame #2: 0x39e8902c libsystem_c.dylib`abort + 76
    frame #3: 0x392d798e libc++abi.dylib`abort_message + 74
    frame #4: 0x392f06e6 libc++abi.dylib`default_terminate_handler() + 254
    frame #5: 0x39928938 libobjc.A.dylib`_objc_terminate() + 192
    frame #6: 0x392ee1b2 libc++abi.dylib`std::__terminate(void (*)()) + 78
    frame #7: 0x392edd16 libc++abi.dylib`__cxa_rethrow + 102
    frame #8: 0x3992880e libobjc.A.dylib`objc_exception_rethrow + 42
    frame #9: 0x2f5615b6 CoreFoundation`CFRunLoopRunSpecific + 642
    frame #10: 0x2f561322 CoreFoundation`CFRunLoopRunInMode + 106
    frame #11: 0x342982ea GraphicsServices`GSEventRunModal + 138
    frame #12: 0x31e181e4 UIKit`UIApplicationMain + 1136
    frame #13: 0x000b8e44 MyApp`main(argc=1, argv=0x27d54d0c) + 116 at main.m:16
    frame #14: 0x39e21ab6 libdyld.dylib`start + 2

Here are the delegate methods:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

    return calendarArray.count;

}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{


    static NSString *cellId = @"CellIdentifier";
    CustomListCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];

    if(cell == nil){

        cell = [[CustomListCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];

    }

    cell.calendar = [calendarArray objectAtIndex:indexPath.row];

    return cell;

}

There are two problems here.

First, when you call dispatch_get_main_queue() you actually get back the main thread, which is not ideal for background processing.

So you need to change that to:

dispatch_queue_t concurrentQueue = dispatch_queue_create("MyQueue", NULL);
dispatch_async(concurrentQueue, ^{
    ... process your data here ...
});

The second problem is that you cannot call UITableView#reloadData from a background thread. So you actually need to schedule just that one on the main thread:

dispatch_async(dispatch_get_main_queue(), ^{
    [list reloadData];
});

The above code for reloadData would go in the block where you processed your data, so your completion block for fetchCalendarsWithCompletion would be something like:

dispatch_queue_t concurrentQueue = dispatch_queue_create("MyQueue", NULL);
dispatch_async(concurrentQueue, ^{
    ... process your data here ...
    dispatch_async(dispatch_get_main_queue(), ^{
        [list reloadData];
    });
});

You should get a console log, something like:

** Terminating app due to uncaught exception ...

The stack trace tells us, that an exception has been thrown and caught within the run loop. The run loop then can nothing do than to re-throw it. The exception happens somewhere in your completion block.

In order to catch an exception, you can set a symbolic breakpoint at symbol objc_exception_throw , or use Xcode's UI to setup an exception breakpoint: Adding an Exception Breakpoint .

I suspect, another thread is altering the array while you iterating over it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM