Reputation: 3472
Im a bit confused here, Im using queues and I got to a point where Im a bit lost.
I have a method named getPeople
who has to fetch pictures of users from the server. In order not to block the app I used this:
-(IBAction)seeMorePeople{
dispatch_queue_t getPeopleQueue = dispatch_queue_create("Pinta Ocupantes", NULL);
dispatch_async(getPeopleQueue, ^{
[self getPeople];
});
dispatch_release(getPeopleQueue);
}
The previous code is executed everytime the user taps a button. Something like "Give me pics from this album" and then another tap "Now I want people's pictures from that other album", diferent pics and different amount of pictures. If the user taps the buttons quite fast, the first queue wont finish fetching the data when the second one is already starting. With in getPeople
I store the data in an NSMutableArray, so when the 2 queues are executing at the same time both are writing on the same Array and the app crashes due to out of bounds exception.
The way getPeople
goes through the data is something like this:
-(void)getPeople:(NSDictionary *)peopleDictionary{
//I receive an NSDictionary and I go through it
NSArray *keys = [peopleDictionary allKeys];
int indexOfArray = 0;
for(NSString *key in keys){
//Complex operation that are not important
[peopleInArray insertObjetAtIndex:indexOfArray];//People in array is a global variable
indexOfArray++;
}
}
What I can't figure out is how to get out of this, I thought of stopping the first queue when the second one comes in, but GCD doesnt have this option... any other way to get this done, hopefully without a major recoding, anyway right now Im out of ideas, so any clue will help.
Upvotes: 8
Views: 24694
Reputation: 1
NSString *lastLoginTime =@" Your last login time";
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDate* date1 = [dateFormat lastLoginTime];
NSDate* date2 = [dateFormat dateFromString:[NSString currentDateTime]];
NSTimeInterval secondsSinceLastLogin = [date2 timeIntervalSinceDate:date1];
// NSLog(@"Seconds Since Last Login: %g", secondsSinceLastLogin);
int hours = (int)secondsSinceLastLogin / 3600;
Upvotes: -1
Reputation: 90551
I would suggest that you avoid synchronizing with semaphores, if possible. The design of GCD is to avoid that. A background task should prepare data but not touch outside state. When the data is prepared, it should dispatch the updating of outside state to either a serial queue or, if the state is bound to the GUI, to the main queue.
So, something like this:
-(void)getPeople:(NSDictionary *)peopleDictionary{
//I receive an NSDictionary and I go through it
NSArray *keys = [peopleDictionary allKeys];
for(NSString *key in keys){
//Complex operation that are not important
dispatch_async(dispatch_get_main_queue(), ^{
[peopleInArray addObject:<whatever>];
});
}
}
If you rather want to replace the array, instead of having two threads adding to it in interleaved fashion, you'd accumulate the whole array in the background and dispatch setting the entirety of peopleInArray
to the main queue.
If you want cancellation, you can implement it yourself with a flag, or you should maybe consider using NSOperation
and NSOperationQueue
instead of GCD. Those have a concept of cancellation built in, although your custom operations still need to check if they've been cancelled and stop working.
Upvotes: 12
Reputation: 989
You are right, there is no way to stop a queue which was dispatched. One thing you could do to make sure that only one queue is accessing getPeople
at the same time is using semaphores (this might be even more interesting).
If you just want to avoid that the users clicks the button multiple times you could use a bool variable stillExecuting
which is set to YES
in your asynchronous dispatch and set to NO
at the end of getPeople
. Before creating getPeopleQueue
you simply check if getPeople
is still executing.
if(!stillExecuting) {
dispatch_queue_t getPeopleQueue = dispatch_queue_create("Pinta Ocupantes", NULL);
dispatch_async(getPeopleQueue, ^{
[self getPeople];
});
dispatch_release(getPeopleQueue);
}
Upvotes: 2