I have a UIViewController and a Category for adding methods to the UIViewController. There is a method in the category:
@implementation UIViewController (AlertAnimationsAndModalViews)
-(void)someAddedMethod
{
UIView *someView;
//do some animation with the view that lasts 3 seconds
//remove the view and return
}
And in any view controller i can call this method
[self someAddedMethod];
However, i only want to allow this method to run one at a time. For example, if i make two calls one after the other
[self someAddedMethod];//call1
[self someAddedMethod];//call2
i want the second call to wait until the first call has completed. I understand that UIView animationWithduration... is run in a seperate thread, and seeing as i cant create iVars in the category i cant really use @synchronized(someObject)..
Any advice?
Thanks in advance!
The method looks like this:
-(void)showTopBannerWithHeight:(CGFloat)height andWidth:(CGFloat)width andMessage:(NSString *)message andDuration:(CGFloat)duration
{
UILabel *messageLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, -height, width, height)];
[self.view.superview addSubview:messageLabel];
[UIView animateWithDuration:0.5
delay:0
options: UIViewAnimationOptionBeginFromCurrentState
animations:^{
messageLabel.frame = CGRectMake(0, 0, SCREEN_WIDTH, height);
}
completion:^(BOOL finished){
[UIView animateWithDuration: 0.5
delay:duration
options: UIViewAnimationOptionBeginFromCurrentState
animations:^{
messageLabel.frame = CGRectMake(0, -height, SCREEN_WIDTH, height);
}
completion:^(BOOL finished){
[messageLabel removeFromSuperview];
}];
}];
}
So i show a "banner" from the top of the screen, wait for a duration (CGFloat) then slide the view out of the screen and remove. As this is in a category i can't add instance variables.. so what i want to achieve is that if more than one call to this method is made, i want the first call to execute without waiting, but each call after that to wait until the previous call has finished.
If its just about the animations you may check if ([someView.layer animationForKey:@"sameKeyAsOnCreation"] == nil)
. Than you will only add an animation, if it is not currently runnning.
You could also use associated objects to store the state on your own (animation running / not running).
Assuming you want to start next animation after previous one has finished.
This way you can use some shared NSMutableArray* _animationQueue
storage:
-(void)someAddedMethod
{
NSTimeInterval duration = 3.0;
void (^animationBlock)() = ^{
//do some animations here
self.view.frame = CGRectOffset(self.view.frame, 40, 0);
};
__block void (^completionBlock)(BOOL) = ^(BOOL finished){
[_animationQueue removeObjectAtIndex:0];
if([_animationQueue count]>0) {
[UIView animateWithDuration:duration animations:_animationQueue[0] completion:completionBlock];
}
};
[_animationQueue addObject:animationBlock];
if([_animationQueue count]==1) {
[UIView animateWithDuration:duration animations:animationBlock completion:completionBlock];
}
}
Note, you don't need any @synchronized
features since everything goes on main thread.
UPDATE: the code below does exactly you need:
-(void)showTopBannerWithHeight:(CGFloat)height andWidth:(CGFloat)width andMessage:(NSString *)message andDuration:(CGFloat)duration
{
static NSMutableArray* animationQueue = nil;
if(!animationQueue) {
animationQueue = [[NSMutableArray alloc] init];
}
void (^showMessageBlock)() = ^{
UILabel *messageLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, width, height)];
messageLabel.text = message;
[self.view.superview addSubview:messageLabel];
[UIView animateWithDuration: 0.5
delay:duration
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
messageLabel.frame = CGRectOffset(messageLabel.frame, 0, -height);
}
completion:^(BOOL finished){
[messageLabel removeFromSuperview];
[animationQueue removeObjectAtIndex:0];
if([animationQueue count]>0) {
void (^nextAction)() = [animationQueue objectAtIndex:0];
nextAction();
}
}];
};
[animationQueue addObject:showMessageBlock];
if([animationQueue count]==1) {
showMessageBlock();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With