如何在 ipad 应用程序的后台线程中显示 UIAlertView?

Posted

技术标签:

【中文标题】如何在 ipad 应用程序的后台线程中显示 UIAlertView?【英文标题】:How to show UIAlertView in background thread in ipad app? 【发布时间】:2013-06-26 11:59:48 【问题描述】:

我需要在后台执行某些代码时显示警报视图。为此,我实现了以下代码。

//this is loading alert  
-(void)showAlert:(NSString *)message 

//    UIAlertView *alert;
alert11 = [[UIAlertView alloc] initWithTitle:@"Updates" message:message delegate:self        
 cancelButtonTitle:@"OK" otherButtonTitles: nil];
   #ifndef ios5_1
  [alert11 autorelease];
  #endif

[alert11 show];



 -(void) showUpdates1:(NSString *)data 
isUpdating = true;
VideoBrowserAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate initApplicationDefaults];
[self performSelectorOnMainThread:@selector(showAlert:) 
                       withObject:@"Please wait while Updating the view...."
                    waitUntilDone:YES];
[appDelegate openExhibitView1];
  //this is update completed alert
 [VideoBrowserAppDelegate addUpdateLog:@"Update is completed" showLog:TRUE     calledFrom:nil];

  

但是在执行SelectorOnMainThread(..) 时,会显示警报,但它会在第二秒内消失。之后openExhibitView1() 完全执行并再次正确显示更新警报。当我们再次单击更新警报的确定按钮时,会显示加载警报。但这不公平。我需要显示加载警报,直到openExhibitView1() 在后台执行,除非我们点击确定按钮。

【问题讨论】:

第一个消失可能是因为第二个出现。这是 alertView 属性..第一个隐藏第二个显示,然后当第二个取消然后第一个弹出。 你的问题也是错误的。你不能在后台线程上做 UI thibgs。 正如@rptwsthi 所说,因此您需要防止应用同时显示多个警报 UI 对象不是线程安全的,不应在除主线程之外的任何东西上使用。我不确定如果 Apple 发现 UI 对象在不是主线程的东西上运行,他们是否会拒绝您的应用,这是因为结果可能出乎意料,因此可能会发生崩溃。 嗨@rptewsthi,我需要在更新内容时显示警报消息,我需要显示“更新警报消息”,完成更新时我需要显示更新完成消息。我怎样才能做到这一点 【参考方案1】:

我建议你写你自己喜欢的 AlertView。但是不要忘记在 iOS 上继承 alertView 是被禁止的。

我建议您创建自己的 UIView 子类并实现方法 showWithMessage、title 和其他。组合视图,然后显示它。

此外,如果您坚持使用警报 .. 这是一篇有趣的帖子,可能会有所帮助...

Multithreading iOS - performing alerts

但我的建议是使用自定义显示动画子类化 UIView。 动画示例:

  - (void)animateShow

    CAKeyframeAnimation *animation = [CAKeyframeAnimation
                                      animationWithKeyPath:@"transform"];
    
    CATransform3D scale1 = CATransform3DMakeScale(0.5, 0.5, 1);
    CATransform3D scale2 = CATransform3DMakeScale(1.2, 1.2, 1);
    CATransform3D scale3 = CATransform3DMakeScale(0.9, 0.9, 1);
    CATransform3D scale4 = CATransform3DMakeScale(1.0, 1.0, 1);
    
    NSArray *frameValues = [NSArray arrayWithObjects:
                            [NSValue valueWithCATransform3D:scale1],
                            [NSValue valueWithCATransform3D:scale2],
                            [NSValue valueWithCATransform3D:scale3],
                            [NSValue valueWithCATransform3D:scale4],
                            nil];
    [animation setValues:frameValues];
    
    NSArray *frameTimes = [NSArray arrayWithObjects:
                           [NSNumber numberWithFloat:0.0],
                           [NSNumber numberWithFloat:0.5],
                           [NSNumber numberWithFloat:0.9],
                           [NSNumber numberWithFloat:1.0],
                           nil];
    [animation setKeyTimes:frameTimes];
    
    animation.fillMode = kCAFillModeForwards;
    animation.removedOnCompletion = NO;
    animation.duration = 0.2;
    
    [self.layer addAnimation:animation forKey:@"show"];


    - (void)animateHide
    
        CAKeyframeAnimation *animation = [CAKeyframeAnimation
                                          animationWithKeyPath:@"transform"];
        
        CATransform3D scale1 = CATransform3DMakeScale(1.0, 1.0, 1);
        CATransform3D scale2 = CATransform3DMakeScale(0.5, 0.5, 1);
        CATransform3D scale3 = CATransform3DMakeScale(0.0, 0.0, 1);
        
        NSArray *frameValues = [NSArray arrayWithObjects:
                                [NSValue valueWithCATransform3D:scale1],
                                [NSValue valueWithCATransform3D:scale2],
                                [NSValue valueWithCATransform3D:scale3],
                                nil];
        [animation setValues:frameValues];
        
        NSArray *frameTimes = [NSArray arrayWithObjects:
                               [NSNumber numberWithFloat:0.0],
                               [NSNumber numberWithFloat:0.5],
                               [NSNumber numberWithFloat:0.9],
                               nil];
        [animation setKeyTimes:frameTimes];
        
        animation.fillMode = kCAFillModeForwards;
        animation.removedOnCompletion = NO;
        animation.duration = 0.1;
        
        [self.layer addAnimation:animation forKey:@"hide"];
        
        [self performSelector:@selector(removeFromSuperview) withObject:self afterDelay:0.105];
    

【讨论】:

不禁止,只是不支持。我已经成功地将 UIAlertView 子类化为支持块,所以这绝对是一个选择。 @Popeye:是的,他们这样做了,而且他们从不说这是不允许的。您甚至自己引用它:“不支持子类化”。这并不意味着它是不允许的。 “知名”...?举一个例子,有人的应用程序仅仅因为它是 UIAlertView 的子类而被拒绝。不是因为它修改了它的视图层次结构,只是因为它子类化了它。同样,我在商店中有几个应用程序使用了这个子类,它们都被接受了(包括这些应用程序的后续更新)。 @Popeye:我只想重复一遍,请你给我举一个例子,说明有人因为她/他继承了 UIAlertView 而被拒绝了一个应用程序。 “显然”无法阅读文档是您的问题,而不是我的问题,因为“不受支持”并不意味着“不允许”。另外,我还要重申我的另一句话,以防你错过它:Apple 批准了我的一些应用程序 + 更新,其中包含子类。对它进行子类化不等于错误地使用系统提供的项目。 @Popeye:你知道,我用过谷歌,但我在任何地方都没有看到任何提到应用被拒绝的消息。但无论如何,如果你想以艰难的方式做到这一点,那就把自己打晕。只要知道有一个更简单的方法。【参考方案2】:

UIKit 不是线程安全的,这意味着最好不要尝试。我自己尝试从后台线程使用警报视图(我忘了在主线程上分派它们)并且行为是出乎意料的,有时是崩溃,有时它在-show 方法之后显示得非常多。 另一点是您不应一次显示多个警报,它们会排队。如果您在显示另一个时显示警报,则最后一个将覆盖第一个,但在解雇后它将再次显示第一个。 最好改变业务逻辑,UIKit + 后台线程是不行的。

【讨论】:

以上是关于如何在 ipad 应用程序的后台线程中显示 UIAlertView?的主要内容,如果未能解决你的问题,请参考以下文章

在后台运行 NSTimer 方法

如何在 iphone/ipad 停靠栏中显示播放项目的详细信息?

如何显示屏幕并运行一些“后台”任务(不使用线程)

如何在我的 iPhone / iPad 的状态栏中显示播放图标

Boost.Thread 线程在发布版本中未在 iPhone/iPad 上启动

如何在 iPhone/iPad/iOS 上显示临时弹出消息