You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建仅首次启动时显示的ViewController?

嘿,这个需求在App开发里太常见啦!我来给你分享几种实用的实现思路,核心就是通过本地存储标记用户是否已经完成过昵称设置,然后在App启动时根据这个标记决定展示哪个页面~

核心思路

我们需要一个持久化的“开关”,记录用户是否已经完成昵称设置:

  • 首次启动App时,这个开关是“关闭”状态,展示昵称设置页面
  • 用户完成设置后,把开关拨到“开启”状态
  • 后续启动App时,检测到开关是“开启”,直接跳转到主页面
方法一:使用UserDefaults(最推荐,轻量快捷)

UserDefaults是iOS里最适合存储这种轻量状态的工具,操作简单,数据会持久化保存到本地,直到App被删除。

步骤1:在App启动时判断状态

你需要在App的入口逻辑里(比如AppDelegate的didFinishLaunchingWithOptions,或者iOS13+的SceneDelegate的scene(_:willConnectTo:options:))添加判断逻辑:

// 以AppDelegate为例(iOS12及以下)
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    let defaults = UserDefaults.standard
    // 读取是否已设置昵称的标记,默认是false(首次启动)
    let hasSetNickname = defaults.bool(forKey: "hasSetNickname")
    
    let window = UIWindow(frame: UIScreen.main.bounds)
    self.window = window
    
    if !hasSetNickname {
        // 首次启动,展示昵称设置页面
        let nicknameVC = NicknameSetupViewController()
        // 如果需要导航栏,可以包一层UINavigationController
        window.rootViewController = UINavigationController(rootViewController: nicknameVC)
    } else {
        // 已完成设置,展示主页面
        let mainVC = MainTabBarController() // 替换成你的主页面VC
        window.rootViewController = mainVC
    }
    
    window.makeKeyAndVisible()
    return true
}

// iOS13+用SceneDelegate的写法
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    guard let windowScene = (scene as? UIWindowScene) else { return }
    
    let window = UIWindow(windowScene: windowScene)
    self.window = window
    
    let defaults = UserDefaults.standard
    let hasSetNickname = defaults.bool(forKey: "hasSetNickname")
    
    if !hasSetNickname {
        let nicknameVC = NicknameSetupViewController()
        window.rootViewController = UINavigationController(rootViewController: nicknameVC)
    } else {
        let mainVC = MainTabBarController()
        window.rootViewController = mainVC
    }
    
    window.makeKeyAndVisible()
}

步骤2:完成昵称设置后更新标记

在昵称设置页面的确认按钮点击事件里,保存用户输入的昵称(如果需要),并更新标记:

class NicknameSetupViewController: UIViewController {
    @IBOutlet weak var nicknameTextField: UITextField!
    
    @IBAction func confirmButtonTapped(_ sender: UIButton) {
        guard let nickname = nicknameTextField.text?.trimmingCharacters(in: .whitespaces), !nickname.isEmpty else {
            // 提示用户输入有效的昵称
            let alert = UIAlertController(title: "提示", message: "请输入你的昵称", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "确定", style: .default))
            present(alert, animated: true)
            return
        }
        
        // 1. 保存用户昵称(可选,根据你的需求)
        UserDefaults.standard.set(nickname, forKey: "userNickname")
        
        // 2. 标记已完成昵称设置
        UserDefaults.standard.set(true, forKey: "hasSetNickname")
        // iOS10+之后UserDefaults会自动同步到本地,这行可以省略,但加上也没问题
        UserDefaults.standard.synchronize()
        
        // 3. 跳转到主页面
        let mainVC = MainTabBarController()
        // 如果你用了导航栏,也可以用push或者popToRootViewController,这里直接替换根视图更彻底
        UIApplication.shared.keyWindow?.rootViewController = UINavigationController(rootViewController: mainVC)
    }
}
方法二:使用Keychain(适合需要跨App删除保留的场景)

如果你的需求是即使用户删除App重装,也不想再显示昵称设置页面(这种场景比较少,比如绑定了用户账号的情况),可以用Keychain来存储标记。不过Keychain的操作比UserDefaults复杂一点,你可以封装一个工具类来简化:

// 简单的Keychain工具类示例
class KeychainHelper {
    static let shared = KeychainHelper()
    
    private let service = "com.yourapp.nickname"
    private let account = "nicknameStatus"
    
    func saveStatus(_ status: Bool) {
        let data = Data(bytes: &status, count: MemoryLayout<Bool>.size)
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: service,
            kSecAttrAccount as String: account,
            kSecValueData as String: data
        ]
        
        // 先删除旧数据(如果有)
        SecItemDelete(query as CFDictionary)
        // 添加新数据
        SecItemAdd(query as CFDictionary, nil)
    }
    
    func getStatus() -> Bool {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: service,
            kSecAttrAccount as String: account,
            kSecReturnData as String: kCFBooleanTrue!,
            kSecMatchLimit as String: kSecMatchLimitOne
        ]
        
        var data: AnyObject?
        let status = SecItemCopyMatching(query as CFDictionary, &data)
        
        if status == errSecSuccess, let data = data as? Data {
            var statusBool = false
            data.copyBytes(to: &statusBool, count: MemoryLayout<Bool>.size)
            return statusBool
        }
        return false
    }
}

// 使用方式和UserDefaults类似,启动时判断:
let hasSetNickname = KeychainHelper.shared.getStatus()
// 完成设置后:
KeychainHelper.shared.saveStatus(true)
方法三:使用Core Data(若已有用户数据体系)

如果你的App已经在用Core Data存储用户相关数据,可以在用户实体里加一个isNicknameSet的布尔字段,启动时查询这个字段来判断是否展示设置页面。这种方式适合有复杂用户数据管理的场景,思路和前面一致:查询字段状态→决定页面→更新字段。

注意事项
  • 测试首次启动效果时,记得删除App后再重新安装,因为UserDefaults/Keychain的数据会保留到App被删除
  • 如果你的App支持多场景(iPad多窗口),要确保在每个场景启动时都做同样的判断
  • UserDefaults不要用来存储敏感数据,昵称这种非敏感信息完全没问题

内容的提问来源于stack exchange,提问作者ilija.trkulja

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:11:08