Come posso impostare programmaticamente InitialViewController
uno Storyboard? Voglio aprire il mio storyboard a una vista diversa a seconda di alcune condizioni che possono variare da un lancio all'altro.
Come posso impostare programmaticamente InitialViewController
uno Storyboard? Voglio aprire il mio storyboard a una vista diversa a seconda di alcune condizioni che possono variare da un lancio all'altro.
Risposte:
Come senza un controller di visualizzazione iniziale fittizio
Assicurarsi che tutti i controller di visualizzazione iniziale abbiano un ID storyboard.
Nello storyboard, deseleziona l'attributo "Is iniziale View Controller" dal primo controller di visualizzazione.
Se esegui la tua app a questo punto, leggi:
Failed to instantiate the default view controller for UIMainStoryboardFile 'MainStoryboard' - perhaps the designated entry point is not set?
E noterai che la proprietà della finestra nel delegato dell'app è ora nulla.
Nell'impostazione dell'app, vai al tuo target e alla Info
scheda. Lì cancella il valore di Main storyboard file base name
. Nella General
scheda, deseleziona il valore per Main Interface
. Questo rimuoverà l'avvertimento.
Crea la finestra e il controller di visualizzazione iniziale desiderato nel application:didFinishLaunchingWithOptions:
metodo del delegato dell'app :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
UIViewController *viewController = // determine the initial view controller here and instantiate it with [storyboard instantiateViewControllerWithIdentifier:<storyboard id>];
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
return YES;
}
didFinishLaunchingWithOptions
viene chiamato quando l'app viene avviata in un nuovo processo. Se vai alla schermata principale e ritorni all'app, questo metodo non verrà più richiamato. (A meno che iOS non si interrompa a causa di vincoli di memoria.) Provare a interrompere l'app e avviare nuovamente dall'IDE. Se il problema persiste, pubblica il problema su SO e sarò felice di aiutarti, amico.
self.window = UIWindow(frame: UIScreen.mainScreen().bounds) var storyboard = UIStoryboard(name: "Main", bundle: nil) var viewController: UIViewController = // self.window!.rootViewController = viewController self.window!.makeKeyAndVisible()
Per tutti gli amanti di Swift , ecco la risposta di @Travis tradotta in SWIFT :
Fai quello che @Travis ha spiegato prima del codice Obiettivo C. Poi,
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
var exampleViewController: ExampleViewController = mainStoryboard.instantiateViewControllerWithIdentifier("ExampleController") as! ExampleViewController
self.window?.rootViewController = exampleViewController
self.window?.makeKeyAndVisible()
return true
}
Il ExampleViewController
sarebbe il nuovo controller vista iniziale che si desidera mostrare.
I passaggi spiegati:
Buona programmazione e buona programmazione!
È possibile impostare a livello di codice il rootViewController della finestra chiave in (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
per esempio:
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if (shouldShowAnotherViewControllerAsRoot) {
UIStoryboard *storyboard = self.window.rootViewController.storyboard;
UIViewController *rootViewController = [storyboard instantiateViewControllerWithIdentifier:@"rootNavigationController"];
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
}
return YES;
}
init()
/ deinit()
, ma senza eseguire viewDidLoad()
o inizializzare correttamente IBOutlet
-s. Assicurati che il codice sia pronto per questo.
Swift 3: aggiorna al codice di @ victor-sigler
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
// Assuming your storyboard is named "Main"
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
// Add code here (e.g. if/else) to determine which view controller class (chooseViewControllerA or chooseViewControllerB) and storyboard ID (chooseStoryboardA or chooseStoryboardB) to send the user to
if(condition){
let initialViewController: chooseViewControllerA = mainStoryboard.instantiateViewController(withIdentifier: "chooseStoryboardA") as! chooseViewControllerA
self.window?.rootViewController = initialViewController
)
}else{
let initialViewController: chooseViewControllerB = mainStoryboard.instantiateViewController(withIdentifier: "chooseStoryboardB") as! chooseViewControllerB
self.window?.rootViewController = initialViewController
)
self.window?.makeKeyAndVisible(
return true
}
È possibile impostare il rootviewcontroller di navigazione come controller della vista principale. Questa idea può essere utilizzata per l'accesso automatico secondo i requisiti dell'applicazione.
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle: nil];
UIViewController viewController = (HomeController*)[mainStoryboard instantiateViewControllerWithIdentifier: @"HomeController"];
UINavigationController navController = [[UINavigationController alloc] initWithRootViewController:viewController];
self.window.rootViewController = navController;
if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1) {
// do stuff for iOS 7 and newer
navController.navigationBar.barTintColor = [UIColor colorWithRed:88/255.0 green:164/255.0 blue:73/255.0 alpha:1.0];
navController.navigationItem.leftBarButtonItem.tintColor = [UIColor colorWithRed:88/255.0 green:164/255.0 blue:73/255.0 alpha:1.0];
navController.navigationBar.tintColor = [UIColor whiteColor];
navController.navigationItem.titleView.tintColor = [UIColor whiteColor];
NSDictionary *titleAttributes =@{
NSFontAttributeName :[UIFont fontWithName:@"Helvetica-Bold" size:14.0],
NSForegroundColorAttributeName : [UIColor whiteColor]
};
navController.navigationBar.titleTextAttributes = titleAttributes;
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
}
else {
// do stuff for older versions than iOS 7
navController.navigationBar.tintColor = [UIColor colorWithRed:88/255.0 green:164/255.0 blue:73/255.0 alpha:1.0];
navController.navigationItem.titleView.tintColor = [UIColor whiteColor];
}
[self.window makeKeyAndVisible];
Per gli utenti di StoryboardSegue
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle: nil];
// Go to Login Screen of story board with Identifier name : LoginViewController_Identifier
LoginViewController *loginViewController = (LoginViewController*)[mainStoryboard instantiateViewControllerWithIdentifier:@“LoginViewController_Identifier”];
navigationController = [[UINavigationController alloc] initWithRootViewController:testViewController];
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
// Go To Main screen if you are already Logged In Just check your saving credential here
if([SavedpreferenceForLogin] > 0){
[loginViewController performSegueWithIdentifier:@"mainview_action" sender:nil];
}
Grazie
Apri mainstoryboard, seleziona prima la vista che desideri avviare, quindi apri Utilità -> Attributi. Sotto "Visualizza controller" viene visualizzato il pulsante di opzione "Is iniziale Visualizza controller". Basta selezionarlo.
--- Alla domanda rivista:
Può essere che tu possa provare questo: scrivi un metodo nella sezione ViewDidLoad della tua vista iniziale e quando il metodo viene eseguito all'avvio dell'applicazione, il metodo attiva un seguito in un'altra vista.
SWIFT 5
Se non hai un ViewController impostato come ViewController iniziale nello storyboard, devi fare 2 cose:
Infine, ora puoi aggiungere il tuo codice in SceneDelegate:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
// Make sure you set an Storyboard ID for the view controller you want to instantiate
window?.rootViewController = storyboard.instantiateViewController(withIdentifier: identifier)
window?.makeKeyAndVisible()
}
Failed to instantiate the default view controller for UIMainStoryboardFile 'Main' - perhaps the designated entry point is not set
avviso che stavo avendo dopo aver deciso di creare un'istanza del mio VC iniziale nel codice. Un punto importante, quando @ rs7 dice "elimina il campo del nome dello storyboard", significano l'intera riga del plist, non solo il contenuto del campo stesso.
Puoi impostare initial view controller
tramite Interface Builder oltre che a livello di programmazione.
Di seguito è l'approccio utilizzato a livello di programmazione.
Obiettivo-C:
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:@"HomeViewController"]; // <storyboard id>
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
return YES;
Veloce:
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
var objMainViewController: MainViewController = mainStoryboard.instantiateViewControllerWithIdentifier("MainController") as! MainViewController
self.window?.rootViewController = objMainViewController
self.window?.makeKeyAndVisible()
return true
Ho creato una classe di routing per gestire la navigazione dinamica e mantenere pulita la classe AppDelegate, spero che possa aiutare anche altri.
//
// Routing.swift
//
//
// Created by Varun Naharia on 02/02/17.
// Copyright © 2017 TechNaharia. All rights reserved.
//
import Foundation
import UIKit
import CoreLocation
class Routing {
class func decideInitialViewController(window:UIWindow){
let userDefaults = UserDefaults.standard
if((Routing.getUserDefault("isFirstRun")) == nil)
{
Routing.setAnimatedAsInitialViewContoller(window: window)
}
else if((userDefaults.object(forKey: "User")) != nil)
{
Routing.setHomeAsInitialViewContoller(window: window)
}
else
{
Routing.setLoginAsInitialViewContoller(window: window)
}
}
class func setAnimatedAsInitialViewContoller(window:UIWindow) {
Routing.setUserDefault("Yes", KeyToSave: "isFirstRun")
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let animatedViewController: AnimatedViewController = mainStoryboard.instantiateViewController(withIdentifier: "AnimatedViewController") as! AnimatedViewController
window.rootViewController = animatedViewController
window.makeKeyAndVisible()
}
class func setHomeAsInitialViewContoller(window:UIWindow) {
let userDefaults = UserDefaults.standard
let decoded = userDefaults.object(forKey: "User") as! Data
User.currentUser = NSKeyedUnarchiver.unarchiveObject(with: decoded) as! User
if(User.currentUser.userId != nil && User.currentUser.userId != "")
{
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let homeViewController: HomeViewController = mainStoryboard.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
let loginViewController: UINavigationController = mainStoryboard.instantiateViewController(withIdentifier: "LoginNavigationViewController") as! UINavigationController
loginViewController.viewControllers.append(homeViewController)
window.rootViewController = loginViewController
}
window.makeKeyAndVisible()
}
class func setLoginAsInitialViewContoller(window:UIWindow) {
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let loginViewController: UINavigationController = mainStoryboard.instantiateViewController(withIdentifier: "LoginNavigationViewController") as! UINavigationController
window.rootViewController = loginViewController
window.makeKeyAndVisible()
}
class func setUserDefault(_ ObjectToSave : Any? , KeyToSave : String)
{
let defaults = UserDefaults.standard
if (ObjectToSave != nil)
{
defaults.set(ObjectToSave, forKey: KeyToSave)
}
UserDefaults.standard.synchronize()
}
class func getUserDefault(_ KeyToReturnValye : String) -> Any?
{
let defaults = UserDefaults.standard
if let name = defaults.value(forKey: KeyToReturnValye)
{
return name as Any
}
return nil
}
class func removetUserDefault(_ KeyToRemove : String)
{
let defaults = UserDefaults.standard
defaults.removeObject(forKey: KeyToRemove)
UserDefaults.standard.synchronize()
}
}
E nel tuo AppDelegate chiama questo
self.window = UIWindow(frame: UIScreen.main.bounds)
Routing.decideInitialViewController(window: self.window!)
Un'altra soluzione con l'utilizzo di Swift 3 e Swift 4 per evitare la forza di lancio è la seguente
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
guard let viewController = storyboard.instantiateViewController(withIdentifier: "YourViewController") as? YourViewController else {
return false
}
self.window?.rootViewController = viewController
self.window?.makeKeyAndVisible()
return true
}
E sotto sta usando con UINavigationController
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
guard let viewController = storyboard.instantiateViewController(withIdentifier: "YourViewController") as? YourViewController else {
return false
}
let navigationController = UINavigationController(rootViewController: viewController)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
return true
}
In AppDelegate.swift
puoi aggiungere il seguente codice:
let sb = UIStoryboard(name: "Main", bundle: nil)
let vc = sb.instantiateViewController(withIdentifier: "YourViewController_StorboardID")
self.window?.rootViewController = vc
self.window?.makeKeyAndVisible()
Ovviamente, devi implementare la tua logica, in base a quali criteri sceglierai un controller di visualizzazione appropriato.
Inoltre, non dimenticare di aggiungere un'identità (seleziona storyboard -> Scena controller -> Mostra la finestra di ispezione identità -> assegna StorboardID).
RISPOSTA AGGIORNATA per iOS 13 e delegato scena:
assicurati di accedere al file info.plist in Manifest scena scena -> Configurazione scena -> Ruolo sessione applicazione -> Elemento 0 ed elimina anche il riferimento allo storyboard principale. Altrimenti riceverai lo stesso avvertimento per non riuscire a creare un'istanza dallo storyboard.
Inoltre, sposta il codice dal delegato dell'app alla scena del metodo delegato scena (_: willConnectTo: options :), poiché è qui che vengono gestiti gli eventi del ciclo di vita.
Qualche giorno fa ho riscontrato la stessa situazione. Un trucco molto semplice ha risolto questo problema. Ho impostato nascosto il mio controller di visualizzazione iniziale prima di launch2. Se il controller di visualizzazione iniziale è il controller corretto, è impostato su visibile in viewDidLoad. Altrimenti, viene eseguito un seguito al controller di visualizzazione desiderato. Funziona perfettamente su iOS 6.1 e versioni successive. Sono sicuro che funziona su versioni precedenti di iOS.
Grazie modificato questo come segue in AppDelegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
//Some code to check value of pins
if pins! == "Verified"{
print(pins)
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "HomePage", bundle: nil)
let exampleViewController: UINavigationController = mainStoryboard.instantiateViewControllerWithIdentifier("SBHP") as! UINavigationController
self.window?.rootViewController = exampleViewController
self.window?.makeKeyAndVisible()
}else{
print(pins)
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let exampleViewController: UINavigationController = mainStoryboard.instantiateViewControllerWithIdentifier("SBUser") as! UINavigationController
self.window?.rootViewController = exampleViewController
self.window?.makeKeyAndVisible()
}
Trovata una soluzione semplice: non è necessario rimuovere il "controllo controller della vista iniziale" dallo storyboard e modificare la scheda Informazioni del progetto e utilizzare makeKeyAndVisible
, basta posizionare
self.window.rootViewController = rootVC;
nel
- (BOOL) application:didFinishLaunchingWithOptions:
rootVC
da instantiateViewControllerWithIdentifier
, giusto?
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = mainStoryboard.instantiateViewController(withIdentifier: "storyBoardid") as! ViewController
let navigationController = UINavigationController(rootViewController: vc)
UIApplication.shared.delegate.window?.rootViewController = navigationController
Un altro modo è presentare viewController,
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = mainStoryboard.instantiateViewController(withIdentifier: "storyBoardid") as! ViewController
self.present(vc,animated:true,completion:nil)
Per prima cosa devi creare l'oggetto del tuo storyboard, quindi cambiare root (se richiesto), quindi prendere riferimento a un particolare controller di visualizzazione che viene spinto controller di visualizzazione corrente (se cambi root) altrimenti è solo presente un nuovo controller di visualizzazione che potresti
Swift 4, Xcode 9
nel file AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let firstVC = storyboard.instantiateViewController(withIdentifier: "firstViewController") as! firstViewController
self.window?.rootViewController = firstVC
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if (PreferenceHelper.getAccessToken() != "") {
let initialViewController = storyboard.instantiateViewController(withIdentifier: "your View Controller Identifier")
self.window?.rootViewController = initialViewController
} else {
let initialViewController = storyboard.instantiateViewController(withIdentifier: "your View Controller identifier")
self.window?.rootViewController = initialViewController
}
self.window?.makeKeyAndVisible()
return true
}
/*
use your view Controller identifier must use it doubles quotes**strong text**
Swift 5 o versioni successive # rendono il controller di visualizzazione del percorso con questo semplice codice. Se si utilizza xcode 11 o versioni successive, inizializzare var window: UIWindow?
in AppDelegate
let rootVC = mainStoryboard.instantiateViewController(withIdentifier: "YOURCONTROLLER") as! YOURCONTROLLER
navigationController.setNavigationBarHidden(true, animated: true)
UIApplication.shared.windows.first?.rootViewController = UINavigationController.init(rootViewController: rootVC)
UIApplication.shared.windows.first?.makeKeyAndVisible()
Se preferisci non cambiare applicationDidFinish, puoi fare il seguente trucco:
Impostare il controller di navigazione come controller della vista iniziale e assegnargli una classe personalizzata "MyNavigationController". Quindi è possibile modificare il controller della vista principale durante viewDidLoad: sostituirà il controller della vista principale impostato nello storyboard.
class MyNavigationController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
if !isLoggedIn() {
viewControllers = [R.storyboard.authentication.loginView()!]
}
}
private func isLoggedIn() -> Bool {
return false
}
}
Seleziona il controller di visualizzazione che desideri aprire per primo e vai alla finestra di ispezione degli attributi. Vai alla scena iniziale e verifica che sia l'opzione del controller della vista iniziale.
Ora questo sarà il controller della vista iniziale che si aprirà per primo all'avvio dell'applicazione.