1

I have a UITableView that gets its data from an array. Populating that array, however, requires downloading and parsing large chucks of data from the Web. That being the case, I'd like perform those operations in a background thread. Here's what I've got so far:

@interface MyClass()

@property (nonatomic, strong) NSArray *model;

@end


@implementation MyClass

- (void) getData {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:SOME_URL]];
       if (data) {
          NSMutableArray *arr = [NSMutableArray array];
          //Populate arr with data just fetched, which can take a while
          dispatch_async(dispatch_get_main_queue(), ^{
             //THIS IS THE STEP I AM UNSURE ABOUT. SHOULD I DO:
             self.model = arr;
             //OR
             self.model = [NSArray arrayWithArray:arr];
             //OR
             self.model = [arr copy];
             //OR
             //something else?
          });
      }
  });
}

@end

Thank you!

Merge Sort
  • 43
  • 5

3 Answers3

1
// you can use any string instead "mythread"
dispatch_queue_t backgroundQueue = dispatch_queue_create("com.mycompany.myqueue", 0);

dispatch_async(backgroundQueue, ^{
   // Send Request to server for Data
    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:SOME_URL]];

    dispatch_async(dispatch_get_main_queue(), ^{
        // Receive Result here for your request and perform UI Updation Task Here
        if ([data length] > 0) {
           // if you receive any data in Response, Parse it either (XML or JSON) and reload tableview new data
        }
    });    
});
Dipen Panchasara
  • 13,480
  • 5
  • 47
  • 57
0
  1. Take a look at this link Understanding dispatch_async and this https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html
  2. You should add DISPATCH_QUEUE_PRIORITY_BACKGROUND instead of DISPATCH_QUEUE_PRIORITY_DEFAULT to run this on the background.

By using DISPATCH_QUEUE_PRIORITY_DEFAULT you just made your task be classified as a normal task. If you have changed it to higher or lower priority, the queue would have run it before or after some other tasks, respectively.

Community
  • 1
  • 1
ipinak
  • 5,739
  • 3
  • 23
  • 41
  • 3
    That's incorrect usage of the queue priority. Either `BACKGROUND` or `DEFAULT` are run off the main queue, so neither will block the UI (they are both run 'in the background'). However, `BACKGROUND` has far lower priority so you might have to wait longer. I wouldn't recommend `BACKGROUND` given that it sounds like the user won't see any data until these tasks finish. – MaxGabriel Oct 13 '13 at 22:39
0

You should do:

self.model = arr;

The reference to self calls the setter, which will release any previous references in that variable and then add a reference count to arr so it doesn't go out of scope. If you were accessing the ivar directly you would do:

[model release];
model = [arr retain];
Joel
  • 15,654
  • 5
  • 37
  • 60
  • If `self.model` is being used accessed from the main queue then the second dispatch to the main queue is needed, as in @JB DeLima's code sample. (E.g. you could be iterating through the array, but then half-way through the iteration the array is changed from another queue and now has a different length). – MaxGabriel Oct 13 '13 at 22:36
  • "self.model = arr;" seems the most sensible to me too since we don't have to iterate through "arr" making copies. What concerns me is modifying the model so abruptly. Imagine the following scenario: (1) tableView:numberOfRowsInSection: is called and returns a number (let's say 1,000) (2)self.model = arr; is executed. self.model now has 500 elements. (3) tableView:cellForRowAtIndexPath: is called to get the data for element 501 or higher. The application will crash. Does this scenario seem possible? I might be mistaken, but I think it could very well happen. – Merge Sort Oct 14 '13 at 02:20
  • By doing: self.model = arr; [self.tableView reloadData]; we prevent the above scenario from happening since reloadData will cause tableView:numberOfRowsInSection: and tableView:cellForRowAtIndexPath: to be called all over again. – Merge Sort Oct 14 '13 at 13:00