I’ve written a method, sortAndSlideHandCards(), that moves 6 UIButtons. Each UIButton is moved to the same position. This is done via a for-each loop and the animateWithDuration method being called on each UIButton.
This method is called for a number of players at the same time. Currently the behaviour results in UIButtons from each player moving but only one at a time. No more than one UIButton can move at any time, as if each animation is waiting for whatever animation that is currently running to stop before attempting it’s own animation, essentially the code is executed sequentially for each player/UIButton. I hoped threading would help me fix this.
when I added the threading code:
backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
sortAndSlideHandCardsGroup = dispatch_group_create();
for(Player* player in _playersArray) {
dispatch_group_async(sortAndSlideHandCardsGroup, backgroundQueue, ^(void) {
[player sortAndSlideHandCards];
});
dispatch_group_wait(sortAndSlideHandCardsGroup,DISPATCH_TIME_FOREVER);
I found that only the first UIButton animation is triggered for each player and that the code gets held up in the runloop “while” because “_animationEnd” never gets set as it would appear the second animation never gets going.
I can see the method launching in its own thread
- (void) sortAndSlideHandCards {
NSLog(@"PLAYER:sortAndSlideHandCards");
CGPoint newCenter;
Card* tempCard = nil;
int count = 1;
float duration = 0.2 / _speedMultiplyer;
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
for(Card *card in _handCards) { //move cards in hand to one postion in hand
if(count == 1) {
tempCard = [[Card alloc] init:_screenWidth:_screenHeight :[card getNumber] :[card getCardWeight] :[card getSuit] :[card getIsSpecial]];
[tempCard setImageSrc: _playerNumber :!_isPlayerOnPhone :count : true :_view: _isAI: [_handCards count]];
newCenter = [tempCard getButton].center;
}
_animationStillRunning = true;
if(![[DealViewController getCardsInPlayArray] containsObject:card] ) {
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionLayoutSubviews animations:^{[card getButton].center = newCenter;} completion:^(BOOL finished){[self animationEnd];}];
while (_animationStillRunning){ //endAnimation will set _animationStillRunning to false when called
//stuck in here after first UIButton when threading code is in play
[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
} //endAnimation will set _animationStillRunning to false when called
}
count++;
}
}
When i comment out the threading code each UIButton (Card) will animate one after another.
With the threading code is in play the first UIButton will animate but during the second run through the for-loop, the code will be stuck in the while-loop, waiting for the animation to end. I’m guessing the second animation doesn’t even start.
I also tried this for the threading code:
[player performSelectorInBackground:@selector(sortAndSlideHandCards) withObject:nil];
Same outcome
Anyone have any ideas why animateWithDuration doesn’t like getting called in a loop when in a thread other than the main one?
You should just be able to kick off the animations you want from whatever UI action is performed. The UIView animateWith… methods return immediately, so you don’t need to worry about waiting for them to complete.
If you have an unknown number of animations to kick off sequentially, use the
delayparameter. Pseudocode:This will increase the delay for each successive animation, so it starts at the end of the previous one.