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

时间:2013-12-01 21:40:58

标签: ios iphone objective-c xcode5 modalviewcontroller

在Xcode 5.0.2中,我为iPhone创建了一个空白的Master Detail应用程序,它可以在模拟器中正常工作:

screenshot

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

所以我创建了2个新文件,LoadingViewController.hLoadingViewController.m(我现在没有自定义代码)。

由于它是Xcode版本5,没有xib文件,而是Main.storyboard - 所以我将View Controller从对象库拖到了故事板上。然后在右侧我选择了LoadingViewController类作为Identity Inspector中的Custom Class:

screenshot

最后我向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>.

1 个答案:

答案 0 :(得分:1)

首先,当您在故事板中实例化控制器时,不使用alloc init,而是使用UIStoryboard方法instantiateViewControllerWithIdentifier:。您需要为您的控制器提供一个“故事板ID”,我可以从您的图像中看到您还没有完成(如果您不了解故事板,请阅读Apple的相关文档)。

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