【问题标题】:When UIButton is pressed and IBAction is called show UIAlertView with activity indicator in it until done当按下 UIButton 并调用 IBAction 时,显示带有活动指示器的 UIAlertView,直到完成
【发布时间】:2014-04-15 08:35:25
【问题描述】:

我有一个非常简单但很烦人的问题。我有两个视图控制器,在第一个中我有一个按钮,它必须去服务器并做一些工作,我想显示一个包含旋转指示器的警报视图,一旦按下按钮就会显示出来当第二个视图控制器加载时被解雇。


我试过这样:

    - (IBAction)logMeInFunction:(id)sender {

    UIAlertView  *waitAlert = [[UIAlertView alloc] initWithTitle:@"Please Wait...." message:nil delegate:self cancelButtonTitle:nil otherButtonTitles: nil];
    [waitAlert show];

  /* Do Some Api testing and stuff */
    [waitAlert dismissWithClickedButtonIndex:0 animated:YES];
    [self performSegueWithIdentifier: @"logMe" sender: self];
}

使用这种方式,警报显示会在第二个视图控制器中立即显示并关闭,而不是显示在第一个以通知用户某些工作正在完成并在第二个消失。 有什么想法吗?

【问题讨论】:

  • 你能显示你的服务器调用吗?最好的选择是在调用完成时隐藏该警报视图,而不是在第二个视图控制器加载时隐藏。
  • 你在后台做什么?我猜可能是异步任务。您应该等到登录任务(例如NSURLConnection)完成后再切换视图。
  • 这就是我得到 json 响应的方式: NSString *strURL2 = [NSString stringWithFormat:@"MyURL"]; NSData *dataURL2 = [NSData dataWithContentsOfURL:[NSURL URLWithString:strURL2]]; NSString *strResult2 = [[NSString alloc] initWithData:dataURL2 encoding:NSUTF8StringEncoding]; NSDictionary *json2 = [strResult2 JSONValue]; NSMutableArray *userExists = [[NSMutableArray alloc] init];我怎样才能完成你的建议?这是我的第一个 JSon 交互应用程序@chrisblomm
  • @Justafinger 请检查我上面的评论

标签: ios objective-c uibutton uialertview uiactivityindicatorview


【解决方案1】:

您的代码的主要问题是您的服务器调用需要是异步的。您现在使用的是同步的 dataWithContentsOfURL,它会阻塞您的主线程。

一个简单的选择是在另一个线程中进行调用。

UIAlertView  *waitAlert = [[UIAlertView alloc] initWithTitle:@"Please Wait...." message:nil delegate:self cancelButtonTitle:nil otherButtonTitles: nil];
[waitAlert show];

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

     NSString *strURL2 = [NSString stringWithFormat:@"MyURL"]; 
     NSData *dataURL2 = [NSData dataWithContentsOfURL:[NSURL URLWithString:strURL2]]; 
     NSString *strResult2 = [[NSString alloc] initWithData:dataURL2 encoding:NSUTF8StringEncoding]; 
     NSDictionary *json2 = [strResult2 JSONValue]; 
     NSMutableArray *userExists = [[NSMutableArray alloc] init];

     dispatch_async(dispatch_get_main_queue(), ^{

         [waitAlert dismissWithClickedButtonIndex:0 animated:YES];
         [self performSegueWithIdentifier: @"logMe" sender: self];
     });
});

【讨论】:

  • 我收到此错误:*** 断言失败 -[UIKeyboardTaskQueue performTask:], /SourceCache/UIKit_Sim/UIKit-2903.2/Keyboard/UIKeyboardTaskQueue.m:388 2014-04-15 11:57 :21.574 score2Win[7060:1003] *** 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“-[UIKeyboardTaskQueue performTask:] 只能从主线程调用。”
  • 我该如何解决? @Justafinger
  • 嗯,它对我有用...你用我的替换了你的完整代码吗?
  • 我发现了问题!我不小心调用了 UIAlertView 两次!
  • 我不小心调用了两次导致问题的waitAlert,感谢您的帮助! @Justafinger,这是一个赞成票:)
【解决方案2】:

不显示 UIAlertview,而是显示带有标签和指示器的 Custome UIView... 试试下面的代码...

UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(0.0,0.0,200.0,200.0)];
customView.layer.cornerRadius = 5.0;
customView.layer.borderColor = [UIColor lightGrayColor].CGColor;
customView.layer.borderWidth = 1.0;
[self.view addSubview:customView];

UILabel* loadingLabel = [[UILabel alloc] initWithFrame:CGRectMake(leftMargin, topMargin, 200.0, 100.0)];
[loadingLabel setNumberOfLines:4];
[loadingLabel setTextAlignment:NSTextAlignmentCenter];
[loadingLabel setText:@"Loading..."];
[customView addSubview:loadingLabel];

UIActivityIndicatorView* loadingIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(leftMargin + 75.0, topMargin + 45.0, 50.0, 50.0)];
[loadingIndicator setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray];
[customView addSubview:loadingIndicator];

一旦服务器工作完成隐藏/删除自定义视图并加载您的下一个视图控制器......

【讨论】:

    【解决方案3】:

    IMO,您需要utilize background thread。主线程将运行HUD,后台线程将访问服务器并执行操作。

    伪代码:

    -(void)sendRequestToServer
    {
         // TODO: Call server to do some function
    
         // Once you are done with server action, you have to come back to MAIN THREAD
         [self performSelectorOnMainThread:@selector(hideHUD) withObject:nil waitUntilDone:NO];
    }
    
    - (IBAction)logMeInFunction:(id)sender 
    {
       [MBProgresssHUD showHUDAddedTo:self.view animated:YES];
       [self performSelectorInBackground:@selector(sendRequestToServer) withObject:nil];
    }
    
    
    -(void)hideHUD
    {
     [MBProgressHUD hideHUDForView:self.view animated:YES];
    }
    

    注意:

    请查看 clink 中给出的示例,并查看 dispatch_asyncdispatch_sync 块。

    希望对你有帮助!

    【讨论】:

      【解决方案4】:

      到可能性:

      1) UIAlertView 或任何其他带有动画的视图将需要一些毫秒的时间才能在屏幕上显示自己。因此,您的服务调用可能会很快,甚至在 UIAlertView 出现在屏幕上之前就给您回复。

      2) UIAlertView 需要一段时间才能在屏幕上显示,因此您的服务器调用可能会使 UIAlertview 等到 Web 服务执行完成,因为两者都在主线程上执行。因此,您应该在显示警报视图后使用延迟调用服务功能,或者您应该使用 GCD。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-08-01
        • 1970-01-01
        • 2016-12-21
        • 2015-02-17
        • 2017-08-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多