Reputation: 944
I am using the following code to change a property called topPlaces
inside a view controller. The line [FlickrFetcher topPlaces]
returns an NSArray
and my property topPlaces
is, of course, also an NSArray.
dispatch_queue_t downloadQueue = dispatch_queue_create("flickr topPlace", NULL);
dispatch_async(downloadQueue, ^{
NSArray *topPlaces = [FlickrFetcher topPlaces];
dispatch_async(dispatch_get_main_queue(), ^{
self.topPlaces = topPlaces;
});
});
dispatch_release(downloadQueue);
However, after the block finishes executing, if I log the value of self.topPlaces
, that is still NULL for some reason. Is there anything I am missing?
Upvotes: 0
Views: 1000
Reputation: 6187
Your ivar will not be set until after your current method has finished. Your call to [FlickrFetcher topPlaces]
is running in parallel to your current method and takes a random amount of time to complete. When it is complete, it makes a call back to the main thread, which is executed on the next iteration of the run loop
This means that in your second dispatch_async()
block you need to call any methods to display the data after setting the ivar.
Upvotes: 3
Reputation: 2668
Please first try to stub self.topPlaces
like this:
dispatch_queue_t downloadQueue = dispatch_queue_create("flickr topPlace", NULL);
dispatch_async(downloadQueue, ^{
NSArray *topPlaces = [FlickrFetcher topPlaces];
dispatch_async(dispatch_get_main_queue(), ^{
self.topPlaces = @[@"test", @"test2", @"test3"];
});
});
Then check the value of self.topPlaces
. If it is still NULL
then I would need to ask what lifetime qualifier does your property self.topPlaces
have (Ex. strong, weak, assign)? If it is weak
then of course the value of topPlaces
will be NULL
after assigning it because there will not be any strong pointers to it. If it is strong
then the value of NSArray *topPlaces = [FlickrFetcher topPlaces];
is NULL
when execution reaches self.topPlaces = topPlaces;
.
The other thing to consider is that when you perform asynchronous actions, execution on the main thread will continue to execute. So, if you are doing the following...
dispatch_queue_t downloadQueue = dispatch_queue_create("flickr topPlace", NULL);
dispatch_async(downloadQueue, ^{
NSArray *topPlaces = [FlickrFetcher topPlaces];
dispatch_async(dispatch_get_main_queue(), ^{
self.topPlaces = topPlaces;
});
});
NSLog(@"topPlaces = %@", self.topPlaces);
Then I would expect self.topPlaces
to always be NULL
when it hits the NSLog
due to the fact that it wont be set until after [FlickrFetcher topPlaces]
has finished and returned and execution continues into the dispatch_async(dispatch_get_main_queue()...
. At that point the value should be set. You may want to do something like the following to ensure you are not only setting the property but perform some sort of update action to update your UI after your asynchronous actions have completed...
dispatch_queue_t downloadQueue = dispatch_queue_create("flickr topPlace", NULL);
dispatch_async(downloadQueue, ^{
NSArray *topPlaces = [FlickrFetcher topPlaces];
dispatch_async(dispatch_get_main_queue(), ^{
[self updateUIWithTopPlaces:topPlaces];
});
});
- (void)updateUIWithTopPlaces:(NSArray*)topPlaces {
self.topPlaces = topPlaces;
// Perform your UI updates here
}
Upvotes: 2