在 ViewDidLoad 上执行 Segue
Posted
技术标签:
【中文标题】在 ViewDidLoad 上执行 Segue【英文标题】:Perform Segue on ViewDidLoad 【发布时间】:2012-01-03 12:58:42 【问题描述】:在 ios 5 中,我有一个带有模式视图控制器的 Storyboard,如果用户第一次使用应用程序,我想显示它,之后我想跳过这个视图控制器。
我设置了一个 NSDefault 键来处理这个问题,但是当我检查它是否已设置然后使用 performSegueWithIdentifier 启动 segue 时,没有任何反应。如果我把这个 segue 放在一个按钮后面,它就可以正常工作......
【问题讨论】:
您是否确认正在通过在调试器中使用断点执行代码?您的代码可能位于错误的位置。 基本上这是在初始视图完成加载之前调用它的问题的症结所在。 【参考方案1】:我回答了一个类似的问题,开发人员希望在开始时显示登录屏幕。我为他整理了一些示例代码,可以在here 下载。解决这个问题的关键是在正确的时间调用东西,如果你想显示这个新的视图控制器,你会在例子中看到你必须使用这样的东西
- (void)viewDidAppear:(BOOL)animated
[super viewDidAppear:animated];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"LoginViewController"];
[vc setModalPresentationStyle:UIModalPresentationFullScreen];
[self presentModalViewController:vc animated:YES];
我还解释了转场和故事板的工作原理,您可以看到 here
【讨论】:
解决方案有效。但是这种方法在跳过之前会显示另一个屏幕。有没有办法避免这种情况? 将其放入 viewDidAppear 似乎会导致底层视图的短暂闪烁,即使设置了动画:NO 也是如此。关于如何防止任何闪光的任何想法? 设置vc.view.hidden = YES
可以避免闪退。
如果您将视图控制器的基本视图设置为隐藏,您将获得一个闪光,但其背景为黑色,而不是底层视图。
这似乎不是正确的解决方案,因为闪存。【参考方案2】:
在 ViewDidLoad 中加载导致“底层”闪烁。我通过以编程方式加载我的 Storyboard 解决了这个问题。因此,在目标/主要故事板下 - 将此留空。然后添加以下内容:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Load Main App Screen
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
HomeScreenVC *homeScreenVC = [storyboard instantiateInitialViewController];
self.window.rootViewController = homeScreenVC;
[self.window makeKeyAndVisible];
// Load Login/Signup View Controller
UIViewController *mainLoginVC = [storyboard instantiateViewControllerWithIdentifier:@"MainLoginVC"];
[mainLoginVC setModalPresentationStyle:UIModalPresentationFullScreen];
[homeScreenVC presentModalViewController:mainLoginVC animated:NO];
return YES;
【讨论】:
以上所有使用 viewDidLoad 的解决方案都导致我的初始屏幕闪烁 - 这个答案是唯一解决它的答案 +1。在 iOS 7 中,使用 presentViewController:animated:completion:. 有一个更好的选择!我很欣赏这个可行的解决方案,但让我向您展示一个不需要破坏默认(主要)故事板加载机制并且涉及更少代码的解决方案 - 请看一下我对这个问题的回答。 如果需要在同一个 StoryBoard 上实例化特定的 VC,可以使用 instantiateViewControllerWithIdentifier【参考方案3】:问题是您要在第一个视图完全添加之前向层次结构添加第二个视图。尝试将您的代码放入:
-(void)viewDidAppear:(BOOL)animated
[super viewDidAppear:animated];
// Present your modal from here
在调用[super viewDidAppear]
后,您可以修改一个完全加载的视图。
【讨论】:
这是我挂断电话的地方;一旦我把我的代码移到这里,就可以工作了! @NJones 这是正确的答案,应该被标记为它。你展示了我们开发人员喜欢知道的东西:为什么?然后是一个简单的解决方案。干杯人。【参考方案4】:在 viewDidLoad 中执行 segue 没有主要问题(当然是在调用 super 之后)。
问题是在应用程序的窗口可见之前执行 segues。 您要显示的 UIViewController 是主故事板的一部分,因此在应用程序开始在应用程序委托中运行它的代码之前将其加载到内存中。在您的情况下,iOS 在您的应用程序窗口收到消息之前调用 viewDidLoad:MakeKeyAndVisible。
重要的部分是可见性。 在窗口不可见的视图层次结构上执行 segue 没有任何作用!
你可以尝试做这样的事情:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
// The window initialized with hidden = YES, so in order to perform the segue we need to set this value to NO.
// After this action, the OS will add the window.rootViewController's view as a subview of the window.
self.window.hidden = NO;
[self.window.rootViewController performSegueWithIdentifier:_IDENTIFIER_ sender:self.window.rootViewController];
// Now that the window is not hidden, we must make it key.
[self.window makeKeyWindow];
return YES;
【讨论】:
【参考方案5】:更新:此解决方案不再适用于 iOS 8。
解决问题的正确方法是在applicationDidBecomeActive:
应用程序委托方法或UIApplicationDidBecomeActiveNotification
通知处理程序中触发segue/present 模态视图控制器。
苹果的文档其实是advises the same:
如果您的应用之前处于后台,您还可以使用它来刷新应用的用户界面。
此解决方案的优势在于它与主故事板加载机制一起使用,因此您无需手动加载任何内容并编写不必要的代码。
我在 iOS 6.1、7.0 和 7.1 上成功使用了这个解决方案,它应该也可以在 iOS 5 上运行。
【讨论】:
对我来说,这似乎是最好的答案。没有闪光灯。不处理窗口可见性。一个(或两个)代码示例会使答案变得更好。 我发现这是最干净的解决方案。例如,在我的应用委托applicationDidBecomeActive:
我有 [self.window.rootViewController presentViewController:[self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:@"loginViewController"] animated:NO completion:nil];
在 8.4 中这仍然会导致初始 VC 在转换之前闪烁。【参考方案6】:
对于斯威夫特:
dispatch_async(dispatch_get_main_queue())
self.performSegueWithIdentifier("toView2", sender: self)
对于 Swift 3:
DispatchQueue.main.async
self.performSegueWithIdentifier("toView2", sender: self)
【讨论】:
DispatchQueue.main.async self.performSegue(withIdentifier: "enterSegue", sender: self) 如果你在 Swift 3.0 上需要它 :) 显然修复了“开始/结束外观转换的不平衡呼叫”警告【参考方案7】:这就是我在 SWIFT 中的做法。这也隐藏了视图控制器。
override func viewWillAppear(animated: Bool)
let prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
let isloggedIn = prefs.objectForKey("isLoggedIn") as? Bool
if (isloggedIn != false)
self.view.hidden = true
else
self.view.hidden = false
override func viewDidAppear(animated: Bool)
super.viewDidAppear(true)
let prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
let isloggedIn = prefs.objectForKey("isLoggedIn") as? Bool
if (isloggedIn != false)
println("this should work")
self.performSegueWithIdentifier("Login", sender: self)
【讨论】:
起初犹豫不决,但这绝对有效。谢谢!【参考方案8】:斯威夫特 3
override func viewWillAppear(_ animated: Bool)
if authPreference.isExist() == true
self.view.isHidden = true
else
self.view.isHidden = false
override func viewDidAppear(_ animated: Bool)
super.viewDidAppear(true)
if authPreference.isExist() == true
navigateToSegue()
【讨论】:
【参考方案9】:我遇到了同样的问题。在找到这个问题之前,我通过在主线程中使用 async 解决了这个问题。这样,该代码将在创建视图后立即由 UI 线程调用。
dispatch_async(dispatch_get_main_queue(), ^
[self performSegueWithIdentifier:@"segueAlbums" sender:self];
);
这段代码可以在viewDidLoad
方法中调用。
【讨论】:
这仍然会导致显示其他屏幕时闪烁和动画【参考方案10】:为 Swift 3 更新
下面的代码 sn-p 允许您加载所需的任何 viewController。在我的例子中,如果用户有一个有效的 facebook 登录令牌,它就是一个 TabBarController。与其他 Swift 3 解决方案相比,此解决方案的优势在于它是即时的,没有屏幕闪烁。
func applicationDidBecomeActive(_ application: UIApplication)
if FBSDKAccessToken.current() != nil
self.window?.rootViewController?.present((self.window?.rootViewController?.storyboard?.instantiateViewController(withIdentifier: "TabBarController"))!, animated: false, completion: nil)
【讨论】:
【参考方案11】:最好的解决办法是这样做:
-(void)viewDidAppear:(BOOL)animated
[super viewDidAppear:animated];
[self performSegueWithIdentifier:@"NameSegue" sender:self];
【讨论】:
【参考方案12】:我为 Swift 3 改编了 @bearMountain answer。
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
window = UIWindow(frame: UIScreen.main.bounds)
let yourInitialVC: UIViewController? = storyboard.instantiateViewController(withIdentifier: "TermsVC")
window?.rootViewController = termsVC
window?.makeKeyAndVisible()
return true
【讨论】:
以上是关于在 ViewDidLoad 上执行 Segue的主要内容,如果未能解决你的问题,请参考以下文章
Swift:如何使滚动视图执行子视图控制器 viewDidLoad
在 ViewController viewDidLoad 之前执行 NSApplicationDelegate 代码
浅论ViewController的加载 -- 解决 viewDidLoad 被提前加载的问题(pushViewController 前执行)