我正在尝试找到一种在Swift中检测应用首次启动的方法。
通常情况下,您会将一个值写入NSUserDefaults以指示应用程序之前已启动过。
let launchedBefore = NSUserDefaults.standardUserDefaults().boolForKey("launchedBefore")
if launchedBefore {
print("Not first launch.")
}
else {
print("First launch, setting NSUserDefault.")
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "launchedBefore")
}
更新 - Swift 3
let launchedBefore = UserDefaults.standard.bool(forKey: "launchedBefore")
if launchedBefore {
print("Not first launch.")
} else {
print("First launch, setting UserDefault.")
UserDefaults.standard.set(true, forKey: "launchedBefore")
}
firstLaunch
是一个可选类型,你没有处理它。此外,它将为 nil,因为你没有注册一个值。 - mattboolForKey
不会返回可选项,如果该值不存在,则返回 false。 - Jon ShierboolForKey
的巧妙改进。 - mattlaunchedBefore
或者其他什么名字。 - Jon Shier我经常需要这个,所以我把它放在一个类别里。
一般用途:
let isFirstLaunch = UserDefaults.isFirstLaunch()
在您的AppDelegate中使用
// use this if you need to refer to it later
var optionallyStoreTheFirstLaunchFlag = false
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
optionallyStoreTheFirstLaunchFlag = UserDefaults.isFirstLaunch()
// .. do whatever else
return true
}
一些重要的考虑:
Swift 4
将以下代码放入UserDefaults+isFirstLaunch.swift文件中:
extension UserDefaults {
// check for is first launch - only true on first invocation after app install, false on all further invocations
// Note: Store this value in AppDelegate if you have multiple places where you are checking for this flag
static func isFirstLaunch() -> Bool {
let hasBeenLaunchedBeforeFlag = "hasBeenLaunchedBeforeFlag"
let isFirstLaunch = !UserDefaults.standard.bool(forKey: hasBeenLaunchedBeforeFlag)
if (isFirstLaunch) {
UserDefaults.standard.set(true, forKey: hasBeenLaunchedBeforeFlag)
UserDefaults.standard.synchronize()
}
return isFirstLaunch
}
}
Swift 3
extension UserDefaults {
var hasLaunchBefore: Bool {
get {
return self.bool(forKey: #function)
}
set {
self.set(newValue, forKey: #function)
}
}
}
Swift 5(属性包装器)
UserDefaultWrapper:
@propertyWrapper
struct UserDefaultWrapper<T> {
let key: String
let defaultValue: T
init(_ key: String, defaultValue: T) {
self.key = key
self.defaultValue = defaultValue
}
var wrappedValue: T {
get {
return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
}
set {
UserDefaults.standard.set(newValue, forKey: key)
}
}
}
UserDefaultsStore:
struct UserDefaultsStore {
@UserDefaultWrapper("has_launch_before", defaultValue: false)
static var hasLaunchBefore: Bool
}
使用方法:
UserDefaultsStore.hasLaunchBefore = false
为了让方法在整个首次启动过程中始终返回true,我对用户n13的答案进行了一些改进。
只需在需要的任何地方使用UIApplication.isFirstLaunch()
即可,并确保在首次执行期间至少调用一次。
Swift 3
import UIKit
private var firstLaunch : Bool = false
extension UIApplication {
static func isFirstLaunch() -> Bool {
let firstLaunchFlag = "isFirstLaunchFlag"
let isFirstLaunch = UserDefaults.standard.string(forKey: firstLaunchFlag) == nil
if (isFirstLaunch) {
firstLaunch = isFirstLaunch
UserDefaults.standard.set("false", forKey: firstLaunchFlag)
UserDefaults.standard.synchronize()
}
return firstLaunch || isFirstLaunch
}
}
Swift 2
import UIKit
private var firstLaunch : Bool = false
extension UIApplication {
static func isFirstLaunch() -> Bool {
let firstLaunchFlag = "isFirstLaunchFlag"
let isFirstLaunch = NSUserDefaults.standardUserDefaults().stringForKey(firstLaunchFlag) == nil
if (isFirstLaunch) {
firstLaunch = isFirstLaunch
NSUserDefaults.standardUserDefaults().setObject("false", forKey: firstLaunchFlag)
NSUserDefaults.standardUserDefaults().synchronize()
}
return firstLaunch || isFirstLaunch
}
}
false
的BOOL键。在启动时读取该键;如果它是false
,则将其设置为true
并显示欢迎信息。下一次启动时,它将是true
,您将不会显示欢迎信息,问题解决了。In case of Swift
if UserDefaults.standard.bool(forKey: "isFirstLaunch") {
UserDefaults.standard.set(true, forKey: "isFirstLaunch")
UserDefaults.standard.synchronize()
}
并在您想要使用的任何地方使用它。
let isFirstLaunch = UserDefaults.standard.value(forKey: "isFirstLaunch") as? Bool
if isFirstLaunch {
//It's the initial launch of application.
}
else {
// not initial launch
}
我对n13的帖子进行了编辑。在我看来,这段代码更加简洁。您可以将其作为类或实例函数调用。
此外,根据苹果文档,除非应用程序即将关闭,否则不应调用 synchronize() ,因为它会定期被调用。我在AppDelegate中的applicationDidEnterBackground()中调用了它。 https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/#//apple_ref/occ/instm/NSUserDefaults/synchronize
if NSUserDefaults().isFirstLaunchForUser("me") {
print("First launch")
} else {
print("Not first launch")
}
if NSUserDefaults.isFirstLaunch() {
print("First launch")
} else {
print("Not first launch")
}
extension NSUserDefaults {
static func isFirstLaunch() -> Bool {
let firstLaunchFlag = "FirstLaunchFlag"
if !standardUserDefaults().boolForKey(firstLaunchFlag) {
standardUserDefaults().setBool(true, forKey: firstLaunchFlag)
// standardUserDefaults().synchronize()
return true
}
return false
}
// For multi user login
func isFirstLaunchForUser(user: String) -> Bool {
if !boolForKey(user) {
setBool(true, forKey: user)
// synchronize()
return true
}
return false
}
}
AppDelegate.swift
let userDefaults = UserDefaults.standard
var currentTimesOfOpenApp:Int = 0
func saveTimesOfOpenApp() -> Void {
userDefaults.set(currentTimesOfOpenApp, forKey: "timesOfOpenApp")
}
func getCurrentTimesOfOpenApp() -> Int {
return userDefaults.integer(forKey: "timesOfOpenApp") + 1
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.currentTimesOfOpenApp = getCurrentTimesOfOpenApp()
return true
}
func applicationWillTerminate(_ application: UIApplication) {
saveTimesOfOpenApp()
self.saveContext()
}
第二步:
如果你想显示时间,你可以从UserDefaults获取此值并在标签上显示。
ViewController.swift
let delegate = UIApplication.shared.delegate as! AppDelegate
let times = delegate.currentTimesOfOpenApp
timesToOpenAppLabel.text = "\(times)"
let applicationLaunchedOnce: Bool = {
let launchedOnce = NSUserDefaults.standardUserDefaults().boolForKey(UserDefaultsService.ApplicationLaunchedOnce)
if launchedOnce {
return launchedOnce
} else {
NSUserDefaults.standardUserDefaults().setBool(true, forKey: UserDefaultsService.ApplicationLaunchedOnce)
NSUserDefaults.standardUserDefaults().synchronize()
return false
}
}()