Ios 允许一次调用一个类别方法(@synchronized)
我有一个UIViewController和一个用于向UIViewController添加方法的类别。该类别中有一种方法:Ios 允许一次调用一个类别方法(@synchronized),ios,objective-c,animation,uiviewanimation,synchronized,Ios,Objective C,Animation,Uiviewanimation,Synchronized,我有一个UIViewController和一个用于向UIViewController添加方法的类别。该类别中有一种方法: @implementation UIViewController (AlertAnimationsAndModalViews) -(void)someAddedMethod { UIView *someView; //do some animation with the view that lasts 3 seconds //remove the vi
@implementation UIViewController (AlertAnimationsAndModalViews)
-(void)someAddedMethod
{
UIView *someView;
//do some animation with the view that lasts 3 seconds
//remove the view and return
}
在任何视图控制器中,我都可以调用这个方法
[self someAddedMethod];
但是,我只希望允许此方法一次运行一个。例如,如果我一个接一个地打两个电话
[self someAddedMethod];//call1
[self someAddedMethod];//call2
我想让第二次通话等到第一次通话结束。我了解UIView动画的持续时间。。。是在一个单独的线程中运行的,鉴于我无法在类别中创建IVAR,我无法真正使用@synchronized(someObject)
有什么建议吗
提前谢谢
编辑
方法如下所示:
-(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];
}];
}];
}
因此,我从屏幕顶部显示一个“横幅”,等待一段时间(CGFloat),然后将视图滑出屏幕并删除。由于这是一个类别,我无法添加实例变量。。
因此,我想要实现的是,如果对该方法进行了多个调用,我希望第一个调用在不等待的情况下执行,但之后的每个调用都要等待,直到前一个调用完成。尝试使用此调用。并在@
synchronized
指令中使用了self
- (void)criticalMethod {
@synchronized(self) {
// Critical code.
}
}
注意:指令
@synchronized()
将任何Objective-C对象(包括self)作为其唯一参数。此对象称为互斥信号量或互斥信号量。它允许一个线程锁定一段代码,以防止其他线程使用它。如果只是关于动画,您可以检查如果([someView.layer animationForKey:@“sameKeyAsOnCreation”]==nil)
。然后,如果动画当前未运行,则仅添加动画
您还可以使用关联的对象存储自己的状态(动画正在运行/未运行)。假设您希望在上一个动画完成后启动下一个动画。 这样,您可以使用一些共享的
NSMutableArray*\u animationQueue
存储:
-(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];
}
}
注意,您不需要任何@synchronized
功能,因为一切都在主线程上进行
更新:下面的代码正是您需要的:
-(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();
}
}
如果确实要等到“3秒动画”完成后再允许再次调用您的方法运行,则此操作将不起作用。是否还要等到动画完成后再运行?是的,请参阅编辑的版本。我最初使用数组实现了类似的实现。它是一个递归方法,将“方法调用”存储在数组中,在该方法结束之前,它将再次调用自身并检查是否添加了任何调用,如果是,则再次添加。但由于将其移动到一个类别中,除非传入一个共享数组,否则我无法使用这些变量,我认为这破坏了使用类别的理由。您可以使用
objc\u setassociated object
在类别中添加ivar。再看看我更新的解决方案。哇,这真有效!谢谢!只要几个问题也可以提高我的理解力如果可以的话。。。当您声明静态数组时,为什么要将其设置为nil,然后检查(!animationQueue)是否为alloc和init?如果你把它设为零,你会一直被分配并初始化它吗?动画末尾的block nextAction()的作用是什么?静态变量animationQueue
的作用方式与全局变量相同。最初它是nil
,每次函数调用都会检查它是否需要分配NSMutableArray
的实例。一旦分配,animationQueue
将变为非零。nextAction
只是队列中缓存的showMessageBlock
对象之一。