1 实现原理

(1)我们会发现许多 App 在一次启动时会显示一个新手引导页(下次启动就不会再显示)
 
(2)其判断原理就是在 AppDelegate 里的 didFinishLaunchingWithOptions 方法中检查 UserDefaults 中是否存在特定的键值:
  • 不存在则说明是第一次运行,我们便把根视图控制器改成引导页,并保存这个特定的键值(Bool 类型即可)。
  • 已存在则说明之前已运行过该应用,那么就显示默认视图。
 
(3)有时我们还想在应用更新后,新版本第一次启动时显示个新功能说明页,其原理同样是判断 UserDefaults 里的键值。只不过这次保存的是版本号,每次将之前保存的版本号与当前应用的版本号做比较:
  • 不同则说明新版本第一次启动。
  • 相同则说明新版本之前已经启动过。
 

2 样例代码

(1)为方便使用,这里对 UserDefaults 进行扩展,增加两个判断是否是第一次启动的方法:
extension UserDefaults {
//应用第一次启动
static func isFirstLaunch() -> Bool {
let hasBeenLaunched = "hasBeenLaunched"
let isFirstLaunch = !UserDefaults.standard.bool(forKey: hasBeenLaunched)
if isFirstLaunch {
UserDefaults.standard.set(true, forKey: hasBeenLaunched)
UserDefaults.standard.synchronize()
}
return isFirstLaunch
} //当前版本第一次启动
static func isFirstLaunchOfNewVersion() -> Bool {
//主程序版本号
let infoDictionary = Bundle.main.infoDictionary!
let majorVersion = infoDictionary["CFBundleShortVersionString"] as! String //上次启动的版本号
let hasBeenLaunchedOfNewVersion = "hasBeenLaunchedOfNewVersion"
let lastLaunchVersion = UserDefaults.standard.string(forKey:
hasBeenLaunchedOfNewVersion) //版本号比较
let isFirstLaunchOfNewVersion = majorVersion != lastLaunchVersion
if isFirstLaunchOfNewVersion {
UserDefaults.standard.set(majorVersion, forKey:
hasBeenLaunchedOfNewVersion)
UserDefaults.standard.synchronize()
}
return isFirstLaunchOfNewVersion
}
}

(2)在 AppDelegate.swift 中调用上面的扩展方法进行判断,并执行相应逻辑。

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? //程序启动
func application(_ application: UIApplication, didFinishLaunchingWithOptions
launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { //判断当前版本是否第一次启动
if UserDefaults.isFirstLaunchOfNewVersion() {
//显示新功能介绍页
print("当前版本第一次启动")
let introductionViewController = IntroductionViewController()
self.window!.rootViewController = introductionViewController
} //判断是否第一次启动(两个都是第一次则以这个为准)
if UserDefaults.isFirstLaunch() {
//显示新手指导页
print("应用第一次启动")
let guideViewController = GuideViewController()
self.window!.rootViewController = guideViewController
} return true
} func applicationWillResignActive(_ application: UIApplication) {
} func applicationDidEnterBackground(_ application: UIApplication) {
} func applicationWillEnterForeground(_ application: UIApplication) {
} func applicationDidBecomeActive(_ application: UIApplication) {
} func applicationWillTerminate(_ application: UIApplication) {
}
}

Swift - 判断应用是否是第一次启动(或当前版本是否第一次启动)的更多相关文章

  1. 解决:阿里云ECS上启动tomcat后,第一次访问时间特别长

    Re在ECS上启动tomcat后,第一次访问时间特别长      2017-04-25 10:16:04 INFO com.world.socket.ServerSocketListener  25- ...

  2. 通过从代码层面分析Linux内核启动来探知操作系统的启动过程

    通过从代码层面分析Linux内核启动来探知操作系统的启动过程 前言说明 本篇为网易云课堂Linux内核分析课程的第三周作业,我将围绕Linux 3.18的内核中的start_kernel到init进程 ...

  3. init进程 && 解析Android启动脚本init.rc && 修改它使不启动android && init.rc中启动一个sh文件

    Android启动后,系统执行的第一个进程是一个名称为init 的可执行程序.提供了以下的功能:设备管理.解析启动脚本.执行基本的功能.启动各种服务.代码的路径:system/core/init,编译 ...

  4. Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7)

    http://blog.chinaunix.net/uid-20543672-id-3157283.html Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3 ...

  5. UEFI启动视频详解:启动分析+N项操作实例

    ============================================================= ※※※※最给力的视频解说※※※※ 2011hiboy全部共享资料:立刻去   ...

  6. Tomcat8源码笔记(七)组件启动Server Service Engine Host启动

    一.Tomcat启动的入口 Tomcat初始化简单流程前面博客介绍了一遍,组件除了StandardHost都有博客,欢迎大家指文中错误.Tomcat启动类是Bootstrap,而启动容器启动入口位于 ...

  7. tomcat 1)启动时不识别执行启动命令 2)启动报错 3)关闭不了,用myEclipse启动时显示jvm_bind,端口占用

  8. 使用servers 启动项目时 ,一直处于启动中, 最后出现无法的问题。

    使用eclipse 中的servers 配置了一个server 来启动项目, 发现无法启动 排除法: 去掉项目配置,单独启动该server ,发现可以启动, 说明是项目出现问题 但是项目并没有报错, ...

  9. Chorme中启动阿里旺旺误点取消启动并记住选择,如何更改。

    今天在Chorme中启动阿里旺旺误点取消启动并记住选择,然后如何也点不开了.从网上找到了一种解决方法: 找到路径   C:\Users\\AppData\Local\Google\Chrome\Use ...

随机推荐

  1. hibernate 一级缓存,二级缓存,查询缓存

    1.一级缓存是session级的缓存,session结束即事务提交,session关闭,缓存清除.效果不大 get方式:一个session内,第二次查询不连数据库.适用于一级缓存 load方式:懒加载 ...

  2. linux环境中,ssh登录报错,Permission denied, please try again.

    问题描述: 今天早上一个同事反应一个问题,通过ssh登录一台测试机的时候,发现两个账号,都是普通账号,一个账号能够登录, 另外一个账号无法登录.问他之前有做过什么变更吗,提到的就是之前有升级过open ...

  3. Java实现快速批量移动文件

    文件移动是计算机资源管理常用的一个操作,这在操作系统中可以通过文件的剪切与复制或鼠标拖动来实现.但是在Java文件的编程实现中,大多是通过复制文件到目的地,再删除所有文件来实现的.这对于小文件来说看不 ...

  4. _DataStructure_C_Impl:图的邻接矩阵存储

    //_DataStructure_C_Impl:邻接矩阵 #include<stdio.h> #include<stdlib.h> #include<string.h&g ...

  5. Java 流(Stream)、文件(File)和IO -- Java ByteArrayInputStream类

    字节数组输入流在内存中创建一个字节数组缓冲区,从输入流读取的数据保存在该字节数组缓冲区中.创建字节数组输入流对象有以下几种方式. 接收字节数组作为参数创建: ByteArrayInputStream ...

  6. VS2015编译提示无法运行“rc.exe”

    使用VSx64命令行编译项目,提示无法运行“rc.exe” 想办法搜索rc.exe和rcdll.dll这两个文件,然后拷贝到C:\Program Files (x86)\Microsoft Visua ...

  7. repr方法字符串输出实例对象的值

    #coding=utf-8 #repr方法字符串输出实例对象的值 class CountFromBy(object): def __init__(self, val=0, incr=1): self. ...

  8. Git和GitHub入门基础

    -----------------------------------------//cd F:/learngit // 创建仓库git init  // 在当前目录下创建空的git仓库------- ...

  9. Lua中的table构造式(table constructor)

    最简单的构造式就是一个空构造式{},用于创建一个空table. 构造式还可以用于初始化数组.例如,以下语句:days = {"Sunday", "Monday" ...

  10. android模拟器与PC的端口映射

    一.概述 Android系统为实现通信将PC电脑IP设置为10.0.2.2,自身设置为127.0.0.1,而PC并没有为Android模拟器系统指定IP,所以PC电脑不能通过IP来直接访问Androi ...