我希望我的应用能够响应远程推送到我的设备。我想要做的是将视图控制器作为对推送通知的响应。
当应用程序运行时,这样做没有问题。从应用程序委托开始,我首先获取根视图控制器并一直向上,以便找到可见的视图控制器并在其上显示一个新的控制器。像魅力一样工作。
当应用程序启动时,我首先显示根视图控制器,然后检查是否有任何缓存的数据存储在设备上,如果是,它会加载一个新的视图控制器来呈现它。有时它需要2s,有时需要让7s说。当应用程序全部完成呈现新的视图控制器时,无法确定操作将花费多长时间。因此,如果我想在发布后立即呈现视图控制器,情况会变得棘手。
目前我使用的hacky版本依赖于dispatch_after
代码段,该代码段会在应用启动后的5s左右触发演示文稿。它在95%的情况下有效,但我不喜欢这个解决方案。
所以我的问题是:当所有模态转换完成且我的应用程序处于"稳定的最终版本时,如何在appDelegate
中收到通知? (这样我可以得到最顶层的视图控制器,并且没有任何伤害地呈现在它上面)状态?
我可以粘贴一些我已经使用的代码,如果这样做会有所帮助。
修改
我被要求粘贴一些代码,以便我如何从app delegate呈现视图控制器。调用application:didFinishLaunchingWithOptions:
并且UIApplicationLaunchOptionsRemoteNotificationKey
词典中有launchOptions
条目时,会调用下面的代码段。
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
UIViewController *controller = [self topViewControllerFromController:self.window.rootViewController];
NSInteger messageID = [userInfo[@"m_id"] integerValue];
MessageViewController *mvc = [[MessageViewController alloc] initWithMessageID:messageID];
mvc.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[controller presentViewController:mvc animated:YES completion:nil];
});
而topViewController
非常简单:
- (UIViewController *)topViewControllerFromController:(UIViewController *)controller
{
if (controller.presentedViewController)
{
UIViewController *presentedViewController = controller.presentedViewController;
return [self topViewControllerFromController:presentedViewController];
}
else if ([controller isKindOfClass:[UINavigationController class]])
{
UINavigationController *navigationController = (UINavigationController *)controller;
return [self topViewControllerFromController:navigationController.visibleViewController];
}
else if ([controller isKindOfClass:[UITabBarController class]])
{
UITabBarController *tabBarController = (UITabBarController *)controller;
return [self topViewControllerFromController:tabBarController.selectedViewController];
}
else
{
return controller;
}
}
现在演示文稿和内容工作正常,并且没有任何问题。我只需要知道所有模态转换何时完成,即。当应用程序很好地呈现另一个。
答案 0 :(得分:2)
如果您有一个固定的视图层次结构,表示要显示的最终视图,您可以:
A)最简单,发布来自[edit:] viewDidAppear:任何“加载链末端”视图控制器的方法的通知。顺便说一下,你应该在一个块中使用一个弱的自我引用,就像你所显示的那样(见下文,在块中使用selfRef,而不是关键字self)。如果你不这样做,它将产生一个保留周期,你的应用程序将保留在内存中(技术上不是泄漏,但具有类似的效果)。在这种情况下,可能无关紧要,因为你的应用程序不太可能在切换topViewController时,因此在这种情况下它不太可能对内存产生净负面影响,但仍然作为一个风格点很重要。 :
appDelegate中的某个地方(例如在应用程序中:didFinishLaunching:withOptions:method)
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
__weak UIViewController *selfRef = self;
[center addObserverForName:@"AllViewsLoaded" object:nil queue:nil usingBlock:^(NSNotification *note)
{
UIViewController *controller = [selfRef topViewControllerFromController: selfRef.window.rootViewController];
NSInteger messageID = [userInfo[@"m_id"] integerValue];
MessageViewController *mvc = [[MessageViewController alloc] initWithMessageID:messageID];
mvc.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[controller presentViewController:mvc animated:YES completion:nil];
}];
然后在viewDidAppear:任何“行结束”视图控制器的方法:
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:@"AllViewsLoaded" object:nil]];
B)或者,你可以定义一个协议 - 例如在你的最终视图控制器的.h文件中:
@protocol FinalViewLoadedAndDisplayedProtocol
- (void)viewFinallyLoaded:(UIViewController*)finalViewControllerThatLoaded;
@end
在你的app appate中定义方法:
- (void)viewFinallyLoaded:(UIViewController*)finalViewControllerThatLoaded {
UIViewController *controller = [self topViewControllerFromController: self.window.rootViewController];
NSInteger messageID = [userInfo[@"m_id"] integerValue];
MessageViewController *mvc = [[MessageViewController alloc] initWithMessageID:messageID];
mvc.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[controller presentViewController:mvc animated:YES completion:nil];
}
将协议支持添加到App delegate .h文件中。然后在最终视图控制器的.m文件中:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
MainClass *appDelegate = (id)[[UIApplication sharedApplication] delegate];
if ([appDelegate respondsToSelector:@selector(viewFinallyLoaded:)]) {
[self.viewDidLoadDelegate viewFinallyLoaded:self];
}
}