70

I am trying to find a way in Swift to detect the first launch.

jscs
  • 63,694
  • 13
  • 151
  • 195
Julian Stellaard
  • 789
  • 1
  • 6
  • 4
  • 3
    "I saw a topic on Stackoverflow but it was outdated (objective-C)." As all the answers below show, the solution to your problem is (and has been, for a while now) pretty much the same whether you code in Objective-C or Swift. – Nicolas Miari Mar 28 '16 at 01:39

9 Answers9

166

Typically you would write a value to NSUserDefaults to indicate that an app has launched before.

let launchedBefore = NSUserDefaults.standardUserDefaults().boolForKey("launchedBefore")
if launchedBefore  {
    print("Not first launch.")
}
else {
    print("First launch, setting NSUserDefault.")
    NSUserDefaults.standardUserDefaults().setBool(true, forKey: "launchedBefore")
}

UPDATE - 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")
}
Jon Shier
  • 12,200
  • 3
  • 35
  • 37
  • 2
    That's not going to work as you've written it. `firstLaunch` is an Optional. You're not grappling with that. Plus, it will be nil because you didn't register a value. – matt Nov 29 '14 at 23:10
  • 12
    It works just fine, as I've tested it. `boolForKey` does not return an optional but false if the value doesn't exist. – Jon Shier Nov 29 '14 at 23:11
  • 1
    Okay! Fine then. :) I didn't realize the clever refinement of `boolForKey`. – matt Nov 29 '14 at 23:12
  • Though I suppose returning an optional could be more useful, as then you could tell the difference between a value being set to false and not being set at all. Though in that case you could use `setValue`, as that take an `AnyObject?`. – Jon Shier Nov 29 '14 at 23:16
  • Things like `objectForKey:` _do_ return an Optional. But `boolForKey:` has special behavior. So that was a good choice! – matt Nov 29 '14 at 23:17
  • 1
    `if firstLaunch { println("Not first launch.") }` that doesn't make much sense ;-) – Tim Jul 03 '15 at 14:50
  • 1
    @TimCastelijns Yeah, I suppose it should be `launchedBefore` or something. – Jon Shier Jul 03 '15 at 20:54
  • @JonShier Any simple way to detect if the user has launched the app first time after update from App Store? – Gurjit Singh Aug 24 '20 at 06:02
  • @GurjitSingh Storing the version number you see on launch should let you detect that. If the version number changes you should know that an update has been made. – Jon Shier Aug 24 '20 at 14:44
  • If you request for it in multiple places in the application, then it will be TRUE for the second and subsequent requests, although it may actually be the first run. Better to use a launch counter. – VyacheslavBakinkskiy Dec 21 '20 at 06:22
44

I kinda always need this so I put it in a category

General Usage:

let isFirstLaunch = UserDefaults.isFirstLaunch()

Usage inside your 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
}

Some important considerations:

  • This flag is only set on the first invocation. If you want to know about the first launch multiple times throughout different screens, set a variable you can later refer to, as per the 'optionallyStoreTheFirstLaunchFlag' example.
  • In iOS, apps are usually never shut down. Apps are backgrounded, foregrounded, state-saved to flash memory, but they are only relaunched if they're force shutdown by the user (rare) or the user restarts their phone. So if you store it in a variable, it could potentially stick around for a long time. Manually reset it once you're done with showing all the tutorial screens and whatnot.

Swift 4

Put the following in 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
    }
}
n13
  • 6,843
  • 53
  • 40
  • FYI to other users, you will need to add in the viewDidAppear section: if isFirstLaunch { instructions here } else { print ("Not first launch")} – David Sanford Jul 22 '16 at 12:33
  • 1
    Well you can use it in any way you like, only keep in mind that it will produce a "true" value only on first _invocation_. If it gets used across multiple views, you will need to be mindful of that. – n13 Jul 26 '16 at 02:35
  • See my answer below if you want it always true during whole first app life until terminated. – jalone Jan 03 '17 at 11:17
  • Also it will produce a "true" on a second launch if for any reason you did not call the method on the first launch. – Mihai Damian Jul 20 '18 at 11:33
  • @MihaiDamian I'm not sure what you're saying. If you don't call it, it won't work. As is generally the case with all code?! Maybe I should clarify usage - maybe you have a code path where it wasn't called on launch? – n13 Jul 22 '18 at 05:22
  • Very bad idea to rely on "iOS apps are usually never shut down". Apple makes extremely clear throughout documentation that the system reserves the right to terminate any process at any time for any reason -- especially on newer versions of iOS that more aggressively manage memory and system resources to conserve energy. – Sam Spencer Apr 11 '19 at 23:42
  • @SamuelSpencer Of course we shouldn't rely on it not being shut down, we just need to keep in mind that 99% of the time when a user pulls out your app, it will continue where it left off. That's different from browsers, computers, where apps are shut down frequently. It's not about relying on anything, it's only about seeing how the usage is like. So I was warning about the fact that an app may live for a much longer time than you'd think. – n13 Apr 12 '19 at 12:54
14

Swift 3

extension UserDefaults {

     var hasLaunchBefore: Bool {
           get {
             return self.bool(forKey: #function)
           }
           set {
             self.set(newValue, forKey: #function)
           }
     }
}

Swift 5 (Property wrappers)

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
}

Usage:

UserDefaultsStore.hasLaunchBefore = false
Roman
  • 147
  • 1
  • 5
8

I refined a bit user n13 answer in order to

  • have the method always return true during the whole first launch
  • be an extension to UIApplication

Just use it wherever you want as UIApplication.isFirstLaunch() and be sure to reach it at least once during first execution.

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
    }
}
jalone
  • 1,953
  • 4
  • 27
  • 46
5

Use NSUserDefaults. Register a BOOL key with a value of false. Read the key at launch time; if it's false, set it to true and show the welcome. Next launch, it will be true, you won't show the welcome, problem solved.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 1
    What about resetting the key? Suppose I roll out my new version of app and User update it then In this case also I want to perform a task (say, display welcome message) then what need to be done? – Tejas Oct 13 '16 at 12:10
4

In case of Swift In applicationdidFinishLaunchingWithOptions in AppDelegate Add:

if UserDefaults.standard.bool(forKey: "isFirstLaunch") {
            UserDefaults.standard.set(true, forKey: "isFirstLaunch")
            UserDefaults.standard.synchronize()
        }

And Use this wherever you want to.

let isFirstLaunch = UserDefaults.standard.value(forKey: "isFirstLaunch") as? Bool

    if isFirstLaunch {
    //It's the initial launch of application.
    }
    else {
    // not initial launch
    }
Community
  • 1
  • 1
Sreedeepkesav M S
  • 1,165
  • 14
  • 16
2

I did an edit of n13's post. This code seems cleaner to me. You can call as a class or instance function.

Also, according to apple docs you shouldn't call synchronize() since it's called periodically, unless the app is about to close. I have it called in the AppDelegate in 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
  }
}
Hanny
  • 1,282
  • 1
  • 13
  • 10
1

you can use UserDefaults to store the times that App has opened

First:

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
}

each time the App is open, you should add the property currentTimesOfOpenApp, so modify this property in the function func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        self.currentTimesOfOpenApp = getCurrentTimesOfOpenApp()
        return true
    }

in addition, when the app is closed, you should save the currentTimesOfOpenApp, that is important!

func applicationWillTerminate(_ application: UIApplication) {
        saveTimesOfOpenApp()
        self.saveContext()
    }

Second:

if you want to show the times, you can get this value form UserDefaults to display it on the Label.

ViewController.swift

let delegate = UIApplication.shared.delegate as! AppDelegate
let times = delegate.currentTimesOfOpenApp
timesToOpenAppLabel.text = "\(times)"

the App is open every time, the currentTimesOfOpenApp will be increase. if you delete the App, this value will be reset as 1.

Frank Li
  • 11
  • 1
-3
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
        }
    }()
Ruslan
  • 35
  • 7