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

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

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

所以我创建了 2 个新文件,LoadingViewController.hLoadingViewController.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://stackoverflow.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://stackoverflow.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>.

【问题讨论】:

    标签: ios iphone objective-c xcode5 modalviewcontroller


    【解决方案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] 来延迟调用。
    猜你喜欢
    • 2013-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-07
    • 2013-04-08
    • 1970-01-01
    • 2012-11-23
    相关资源
    最近更新 更多