在 iOS 5 中,我有一个带有模式视图控制器的 Storyboard,如果它是用户第一次使用应用程序,我想显示它,之后我想跳过这个视图控制器。
我设置了一个 NSDefault 键来处理这个问题,但是当我检查它是否已设置然后使用 performSegueWithIdentifier 来启动 segue 时,没有任何反应。如果我把这个segue放在一个按钮后面,它就可以正常工作......
在 iOS 5 中,我有一个带有模式视图控制器的 Storyboard,如果它是用户第一次使用应用程序,我想显示它,之后我想跳过这个视图控制器。
我设置了一个 NSDefault 键来处理这个问题,但是当我检查它是否已设置然后使用 performSegueWithIdentifier 来启动 segue 时,没有任何反应。如果我把这个segue放在一个按钮后面,它就可以正常工作......
我回答了一个类似的问题,开发人员希望在一开始就显示登录屏幕。我为他整理了一些示例代码,可以在这里下载。解决这个问题的关键是在正确的时间调用东西,如果你想显示这个新的视图控制器,你会在例子中看到你必须使用这样的东西
- (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];
}
我还解释了 segues 和 storyboards 的工作原理,你可以在这里看到
在 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;
}
问题是您要在第一个视图完全添加之前向层次结构添加第二个视图。尝试将您的代码放入:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
// Present your modal from here
}
调用后[super viewDidAppear]
,您有一个完全加载的视图要修改。
在 viewDidLoad 中执行 segues 没有主要问题(当然是在调用 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;
}
更新:此解决方案不再适用于 iOS 8。
解决问题的正确方法是在applicationDidBecomeActive:
应用程序委托方法或UIApplicationDidBecomeActiveNotification
通知处理程序中触发 segue/present 模态视图控制器。
苹果的文档实际上建议相同:
如果您的应用以前在后台,您还可以使用它来刷新应用的用户界面。
该解决方案的优点是它与主故事板加载机制一起使用,因此您无需手动加载任何内容并编写不必要的代码。
我在 iOS 6.1、7.0 和 7.1 上成功使用了这个解决方案,它也应该适用于 iOS 5。
对于斯威夫特:
dispatch_async(dispatch_get_main_queue()) {
self.performSegueWithIdentifier("toView2", sender: self)
}
对于斯威夫特 3:
DispatchQueue.main.async {
self.performSegueWithIdentifier("toView2", sender: self)
}
这就是我在 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)
}
}
斯威夫特 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()
}
}
我有同样的问题。在找到这个问题之前,我通过在主线程中使用 async 解决了这个问题。这样,此代码将在创建视图后立即由 UI 线程调用。
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:@"segueAlbums" sender:self];
});
可以在viewDidLoad
方法中调用此代码。
为 Swift 3 更新
下面的代码片段允许您加载所需的任何 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)
}
}
最好的解决方案是这样做:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[self performSegueWithIdentifier:@"NameSegue" sender:self];
}
我为 Swift 3 改编了@bearMountain 答案。
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
}