向 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