Reputation: 15
I'm trying to write this method that returns an NSArray
. My NSMutableArray
(friendUsers) adds the objects right, but outside the dispatch_async the array is empty.
I try to add the users in the main queue ( as ashowed) but the array is empty to. Any ideas ? Thanks for all your help.
- (NSArray *)checkUsersInGroup {
NSMutableArray *friendUsers = [[NSMutableArray alloc] init];
dispatch_queue_t checkUSers = dispatch_queue_create("CheckUsers", NULL);
dispatch_async(checkUSers, ^{
NSArray *totalUsers = [VVDataRead lecturaDades];
NSArray *usersToSearch = [_grup objectForKey:@"groupFriends"];
for (NSString *tempUserId in usersToSearch){
for (NSDictionary *user in totalUsers){
NSString *id = [user objectForKey:@"id"];
if ([tempUserId isEqualToString:id])
dispatch_async(dispatch_get_main_queue(), ^{
[friendUsers addObject:user];
});
}
}
});
NSLog(@"people:%@",friendUsers);
return [friendUsers copy];
}
Upvotes: 0
Views: 3765
Reputation: 24031
you can use blocks, it can make your life easier in this case.
- (void)checkUsersInGroupWithCompleteBlock:(void(^)(NSMutableArray * resultArray))completeBlock {
NSMutableArray *friendUsers = [[NSMutableArray alloc] init];
dispatch_queue_t checkUSers = dispatch_queue_create("CheckUsers", NULL);
dispatch_async(checkUSers, ^{
NSArray *totalUsers = [VVDataRead lecturaDades];
NSArray *usersToSearch = [_grup objectForKey:@"groupFriends"];
for (NSString *tempUserId in usersToSearch){
for (NSDictionary *user in totalUsers){
NSString *id = [user objectForKey:@"id"];
if ([tempUserId isEqualToString:id])
dispatch_async(dispatch_get_main_queue(), ^{
[friendUsers addObject:user];
});
}
}
// call the complete block with the result when you finished
if (completeBlock) completeBlock(friendUsers);
});
}
...and here is how you can call the method:
- (void)anyMethod {
// ... do whetever you want here before
[self checkUsersInGroupWithCompleteBlock:^(NSMutableArray *resultArray) {
NSLog(@"%@", resultArray);
}];
// ... or after
}
EDITED:
NOTE: here is another possible solution, but in your case it just suspends the main thread (which is definitely bad), so you won't gain anything with this solution but pain on the main thread, but if you are on two background threads, this solution can give a very nice example of synchronisation between the threads.
- (NSArray *)checkUsersInGroup {
NSMutableArray *friendUsers = [[NSMutableArray alloc] init];
// our semaphore is here
dispatch_semaphore_t _semaphore = dispatch_semaphore_create(0);
dispatch_queue_t checkUSers = dispatch_queue_create("CheckUsers", NULL);
dispatch_async(checkUSers, ^{
NSArray *totalUsers = [VVDataRead lecturaDades];
NSArray *usersToSearch = [_grup objectForKey:@"groupFriends"];
for (NSString *tempUserId in usersToSearch){
for (NSDictionary *user in totalUsers){
NSString *id = [user objectForKey:@"id"];
if ([tempUserId isEqualToString:id])
dispatch_async(dispatch_get_main_queue(), ^{
[friendUsers addObject:user];
});
}
}
// the process finished
dispatch_semaphore_signal(_semaphore);
});
// ... we are wainitng for the semaphore's signal
dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
dispatch_release(_semaphore);
NSLog(@"people:%@",friendUsers);
return [friendUsers copy];
}
Upvotes: 3
Reputation: 2044
There are number of strategies to solve this, but as your operation happens on a background thread, returning the array isn't one of them. You could use NSNotificationCenter
to signal that the task as finished and read the array. i.e.
- (void)checkUsersInGroup {
NSMutableArray *friendUsers = [[NSMutableArray alloc] init];
dispatch_queue_t checkUSers = dispatch_queue_create("CheckUsers", NULL);
dispatch_async(checkUSers, ^{
NSArray *totalUsers = [VVDataRead lecturaDades];
NSArray *usersToSearch = [_grup objectForKey:@"groupFriends"];
for (NSString *tempUserId in usersToSearch){
for (NSDictionary *user in totalUsers){
NSString *id = [user objectForKey:@"id"];
if ([tempUserId isEqualToString:id])
dispatch_async(dispatch_get_main_queue(), ^{
[friendUsers addObject:user];
});
}
}
// Signal background task is finished
// Make sure to add an observer to this notification
[[NSNotificationCenter defaultCenter] postNotificationName:@"friendsAddLiteral"
object:nil];
});
}
//this method will respond to the notification
- (void) onFriendsAdded:(NSNotification*)notif {
//do something on the main thread
}
Upvotes: 0