向 Master-Detail 应用程序添加模式加载视图(在 applicationDidBecomeActive 方法中)

Posted

技术标签:

【中文标题】向 Master-Detail 应用程序添加模式加载视图(在 applicationDidBecomeActive 方法中)【英文标题】:Adding a modal loading view to Master-Detail application (in applicationDidBecomeActive method) 【发布时间】:2013-12-01 21:40:58 【问题描述】:

在 Xcode 5.0.2 中,我为 iPhone 创建了一个空白的 Master Detail 应用程序,它在模拟器中运行良好:

当 iPhone 应用程序正在启动或从后台唤醒时,我想在中间显示一个带有标签“正在加载...”的模式视图,获取一个网页(在这个测试用例中;在真实的应用程序,这将是游戏更新和玩家得分),然后关闭网页上的模式视图获取完成或错误或超时。

所以我创建了 2 个新文件,LoadingViewController.h 和 LoadingViewController.m(我目前没有自定义代码)。

因为它是 Xcode 版本 5,所以没有 xib 文件,而是 Main.storyboard - 所以我将一个视图控制器从对象库拖到故事板上。然后在右侧我选择了 LoadingViewController 类作为 Identity Inspector 中的自定义类:

最后我在 AppDelegate.m 中添加了 3 个方法:

- (void)applicationDidBecomeActive:(UIApplication *)application

    [self showLoadingView];


- (void)applicationWillResignActive:(UIApplication *)application

    [self dismissLoadingView];


- (void)showLoadingView

    NSLog(@"%s", __PRETTY_FUNCTION__);
    [self fetchHttp];
    LoadingViewController *other = [[LoadingViewController alloc] init];
    [self.window.rootViewController presentViewController:other animated:YES completion:nil];


- (void)dismissLoadingView

    NSLog(@"%s", __PRETTY_FUNCTION__);
    [self.window.rootViewController dismissViewControllerAnimated:YES completion:nil];


- (void)fetchHttp

    NSLog(@"%s", __PRETTY_FUNCTION__);
    NSString *urlAsString = @"http://***.com";
    NSURL *url = [NSURL URLWithString:urlAsString];
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    [NSURLConnection
     sendAsynchronousRequest:urlRequest
     queue:queue
     completionHandler:^(NSURLResponse *response,
                         NSData *data,
                         NSError *error) 

         if ([data length] > 0  &&
             error == nil) 
             NSString *html = [[NSString alloc] initWithData:data
                                                    encoding:NSUTF8StringEncoding];
             NSLog(@"HTML = %u", [html length]);
         
         else if ([data length] == 0 &&
                  error == nil) 
             NSLog(@"Nothing was downloaded.");
         
         else if (error != nil) 
             NSLog(@"Error happened = %@", error);
         

         // XXX how to dismiss the modal view here, it's a different thread?
     ];

不幸的是,现在我在模拟器中出现黑屏和以下输出:

2013-12-01 22:37:01.332 LoadingTest[3840:a0b] -[AppDelegate showLoadingView]
2013-12-01 22:37:01.334 LoadingTest[3840:a0b] -[AppDelegate fetchHttp]
2013-12-01 22:37:01.857 LoadingTest[3840:a0b] Unbalanced calls to begin/end appearance transitions for <UINavigationController: 0x8c74f10>.
2013-12-01 22:37:01.870 LoadingTest[3840:4607] HTML = 196885

我很难理解如何在这里使用故事板(如果可能的话,我想使用它)-因为我正在阅读的书(在 O'Reilly Safari 中)都在谈论 xib 文件(可能适用于较旧的 Xcode 版本?)。

而且我不明白如何从我的 completionHandler 中关闭模式视图,因为它位于不同的线程中,我可能不应该从那里调用 dismissViewControllerAnimated

更新:

我在视图中添加了一个“故事板 ID”:loadingView,并将以下代码添加到 AppDelegate.m

- (void)showLoadingView

    NSLog(@"%s", __PRETTY_FUNCTION__);
    [self fetchHttp];

    UIStoryboard *board = [self.window.rootViewController storyboard]; //[UIStoryboard storyboardWithName:@"Main.storyboard" bundle:nil];
    LoadingViewController *other = [board instantiateViewControllerWithIdentifier:@"loadingView"];
    [self.window.rootViewController presentViewController:other animated:YES completion:nil];


- (void)fetchHttp

    NSLog(@"%s", __PRETTY_FUNCTION__);
    NSString *urlAsString = @"http://***.com";
    NSURL *url = [NSURL URLWithString:urlAsString];
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];

    [NSURLConnection
     sendAsynchronousRequest:urlRequest
     queue:[NSOperationQueue mainQueue]
     completionHandler:^(NSURLResponse *response,
                         NSData *data,
                         NSError *error) 

         if ([data length] > 0  &&
             error == nil) 
             NSString *html = [[NSString alloc] initWithData:data
                                                    encoding:NSUTF8StringEncoding];
             NSLog(@"HTML = %u", [html length]);
         
         else if ([data length] == 0 &&
                  error == nil) 
             NSLog(@"Nothing was downloaded.");
         
         else if (error != nil) 
             NSLog(@"Error happened = %@", error);
         

         [self dismissLoadingView];
     ];

但现在我收到下面的警告并且loadingView 没有被解除(可能是因为网页加载速度比显示的模式视图快?):

2013-12-03 01:49:12.208 LoadingTest[631:70b] -[AppDelegate showLoadingView]
2013-12-03 01:49:12.210 LoadingTest[631:70b] -[AppDelegate fetchHttp]
2013-12-03 01:49:12.756 LoadingTest[631:70b] HTML = 200949
2013-12-03 01:49:12.757 LoadingTest[631:70b] -[AppDelegate dismissLoadingView]
2013-12-03 01:49:12.757 LoadingTest[631:70b] Warning: Attempt to dismiss from view controller <UINavigationController: 0x8a70ce0> while a presentation or dismiss is in progress!
2013-12-03 01:49:12.844 LoadingTest[631:70b] Unbalanced calls to begin/end appearance transitions for <UINavigationController: 0x8a70ce0>.

【问题讨论】:

【参考方案1】:

首先,当您在情节提要中实例化控制器时,您不使用 alloc init,而是使用 UIStoryboard 方法instantiateViewControllerWithIdentifier:。你需要给你的控制器一个“Storyboard ID”,我可以从你的图片中看到你还没有完成(如果你不理解storyboard,请阅读Apple的文档)。

您可以从完成处理程序中关闭您的模式视图 - 处理程序是在异步操作完成后调用的代码,因此您应该使用 [NSOperationQueue mainQueue] 作为队列参数。

【讨论】:

不会使用 [NSOperationQueue mainQueue] 冻结我的 UI 还是仅用于 completionHandler @AlexanderFarber,正如文档所说,“队列——当请求完成或失败时,处理程序块被分派到的操作队列。”所以这个队列只用于完成块,异步进程仍然在后台线程上运行。 谢谢,你对我更新的问题有什么建议吗? @AlexanderFarber,有很多方法可以解决这个问题。一种简单的方法是使用 [self performSelector:@selector(fetchHttp) withObject:nil afterDelay:1.0] 而不是 [self fetchHttp] 来延迟调用。

以上是关于向 Master-Detail 应用程序添加模式加载视图(在 applicationDidBecomeActive 方法中)的主要内容,如果未能解决你的问题,请参考以下文章

Swift Master-Detail 模板问题(iOS 8 beta 3)

核心数据 - NSManagedObjectContext 在 Master-Detail 应用程序中返回 nil

scrollsToTop 不适用于简单的 Master-Detail iOS 应用程序

Android:向活动添加锁定模式

桥接模式

向现有应用程序添加审计的良好模式或框架? [关闭]