views:

535

answers:

1

I am working with network request - response in Objective-C. There is something with asynchronous model that I don't understand.

In summary, I have a view that will show my statuses from 2 social networks: Twitter and Facebook. When I clicked refresh, it will call a model manager. That model manager will call 2 service helpers to request for latest items. When 2 service helpers receive data, it will pass back to model manager and this model will add all data into a sorted array.

What I don't understand here is that : when response from social networks come back, how many threads will handle the response. From my understanding about multithreading and networking (in Java), there must have 2 threads handle 2 responses and those 2 threads will execute the code to add the responses to the array. So, it can have race condition and the program can go wrong right? Is it the correct working model of iphone objective-C? Or they do it in a different way that it will never have race condition and we don't have to care about locking, synchronize?

Here is my example code:

ModelManager.m

- (void)updateMyItems:(NSArray *)items {
    self.helpers = [self authenticatedHelpersForAction:NCHelperActionGetMyItems];
    for (id<NCHelper> helper in self.helpers) {
        [helper updateMyItems:items]; // NETWORK request here
    }
}

- (void)helper:(id <NCHelper>)helper didReturnItems:(NSArray *)items {
     [self helperDidFinishGettingMyItems:items callback:@selector(model:didGetMyItems:)];
         break;                     
    }
}

// some private attributes
int *_currentSocialNetworkItemsCount = 0; // to count the number of items of a social network
- (void)helperDidFinishGettingMyItems:(NSArray *)items {
        for (Item *item in items) {
            _currentSocialNetworkItemsCount ++;
        }            
        NSLog(@"count: %d", _currentSocialNetworkItemsCount);
        _currentSocialNetworkItemsCount = 0;
}

I want to ask if there is a case that the method helperDidFinishGettingMyItems is called concurrently. That means, for example, faceboook returns 10 items, twitter returns 10 items, will the output of count will ever be larger than 10?

And if there is only one single thread, how can the thread finishes parsing 1 response and jump to the other response because, IMO, thread is only executed sequently, block of code by block of code

+1  A: 

Yes, there is probably a thread per network request. The trick is to handle the response on the main thread. You should have something like this:

- (void)helper:(id <NCHelper>)helper didReturnItems:(NSArray *)items;
{
    [self performSelectorOnMainThread:@selector(helperDidFinishGettingMyItems:)
                           withObject:items
                        waitUntilDone:NO];
}

Putting the response back onto the main thread will avoid a whole bunch of multithreading problems.

Also, the output of count will never be larger than 10. It's just that multiple threads may be running helperDidFinishGettingMyItems: at the same time. They won't automatically combine the two arrays.

The counter could possibly be more than 10, because multiple threads could be increasing that ivar at the same time.

Tom Dalling
If we put it back to the main thread, will it freeze our screen? "It's just that multiple threads may be running helperDidFinishGettingMyItems: at the same time. They won't automatically combine the two arrays."I don't understand this. If two threads run that method at the same time and run the for loop at the same time as well, and my counter is an attribute of the object (which is shared), I think that it can go up to more than 10, am I missing something?
vodkhang
The freeze is caused by waiting for the response, but that's why you wait on a background thread. Once the response has arrived the freeze is finished, so the main thread can handle the response. You are right, the counter could be more than 10. Sorry, I didn't realise that the counter was an ivar.
Tom Dalling