Avatar ·

Как программно установить начальный view controller в Storyboard?

Привет всем! Я новичок в iOS разработке и использую Swift. У меня есть Storyboard с несколькими View Controllers. По умолчанию в Storyboard я поставил стрелку на LoginViewController, чтобы он запускался первым. Но теперь мне нужно, чтобы приложение проверяло, авторизован ли пользователь, и в зависимости от этого показывало либо LoginViewController, либо MainViewController. Я знаю, что можно изменить начальный контроллер в настройках Storyboard, но это статично. Как мне сделать это программно? Я пытался что-то сделать в `AppDelegate`, но не понимаю, как правильно получить доступ к Storyboard и установить нужный контроллер. Вот мой текущий код в `AppDelegate`: ```swift func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { let isLoggedIn = UserDefaults.standard.bool(forKey: "isLoggedIn") if isLoggedIn { // Здесь нужно показать MainViewController } else { // Здесь нужно показать LoginViewController } return true } ``` Подскажите, как правильно реализовать такую логику? Желательно с примером кода. Заранее спасибо! <<>>

Программная установка начального контроллера через AppDelegate

Проблема, которую вы описываете, очень распространена. Решение заключается в том, чтобы вручную загрузить Storyboard, создать экземпляр нужного View Controller и установить его как rootViewController для окна приложения. Вот пошаговое руководство.

Шаг 1: Настройка Storyboard

Убедитесь, что у ваших View Controllers в Storyboard заданы Storyboard ID. Для этого:

  • Откройте Storyboard
  • Выберите нужный View Controller
  • В инспекторе Identity Inspector (правая панель) найдите поле Storyboard ID
  • Задайте уникальные идентификаторы, например: LoginViewControllerID и MainViewControllerID

Шаг 2: Код в AppDelegate

Вот полный рабочий код для Swift 5+:

import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        // Создаем окно с размерами экрана
        window = UIWindow(frame: UIScreen.main.bounds)
        
        // Загружаем Storyboard
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        
        // Проверяем, авторизован ли пользователь
        let isLoggedIn = UserDefaults.standard.bool(forKey: "isLoggedIn")
        
        var initialViewController: UIViewController
        
        if isLoggedIn {
            // Если пользователь авторизован — показываем главный экран
            initialViewController = storyboard.instantiateViewController(withIdentifier: "MainViewControllerID")
        } else {
            // Если нет — экран логина
            initialViewController = storyboard.instantiateViewController(withIdentifier: "LoginViewControllerID")
        }
        
        // Устанавливаем начальный контроллер
        window?.rootViewController = initialViewController
        window?.makeKeyAndVisible()
        
        return true
    }
}

Шаг 3: Важные моменты

  • Storyboard ID должны точно совпадать с теми, что вы указали в Storyboard
  • Уберите стрелку начального контроллера из Storyboard, иначе будет конфликт
  • Если используете SceneDelegate (iOS 13+), код нужно поместить туда, а не в AppDelegate

Альтернатива: Работа через SceneDelegate (iOS 13+)

import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    
    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = (scene as? UIWindowScene) else { return }
        
        window = UIWindow(windowScene: windowScene)
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        
        let isLoggedIn = UserDefaults.standard.bool(forKey: "isLoggedIn")
        let identifier = isLoggedIn ? "MainViewControllerID" : "LoginViewControllerID"
        let initialVC = storyboard.instantiateViewController(withIdentifier: identifier)
        
        window?.rootViewController = initialVC
        window?.makeKeyAndVisible()
    }
}

Этот подход даёт полный контроль над тем, какой экран показывается первым, и идеально подходит для сценариев с авторизацией, онбордингом или A/B тестированием.

<<>>

Использование NavigationController как контейнера

Другой популярный подход — не менять rootViewController, а использовать UINavigationController, который будет программно заменять свой корневой контроллер. Это удобно, если у вас уже есть навигация между экранами.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    window = UIWindow(frame: UIScreen.main.bounds)
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    
    let isLoggedIn = UserDefaults.standard.bool(forKey: "isLoggedIn")
    let initialVC: UIViewController
    
    if isLoggedIn {
        initialVC = storyboard.instantiateViewController(withIdentifier: "MainViewControllerID")
    } else {
        initialVC = storyboard.instantiateViewController(withIdentifier: "LoginViewControllerID")
    }
    
    // Оборачиваем в NavigationController
    let navigationController = UINavigationController(rootViewController: initialVC)
    window?.rootViewController = navigationController
    window?.makeKeyAndVisible()
    
    return true
}

Плюсы этого подхода:

  • Сохраняет стандартную навигацию (back button, push/pop)
  • Легко добавить анимацию перехода между экранами
  • Удобно, если в будущем понадобится показывать разные стеки контроллеров

Выберите тот способ, который лучше подходит под архитектуру вашего приложения. Оба решения рабочие и используются в production-проектах.