54

I have a switch called soundSwitch, I'm saving the state of the button using an userDefault as such:

@IBAction func soundsChanged(sender: AnyObject) {
        if soundSwitch.on{
            defaults.setBool(true, forKey: "SoundActive")
            print("Sound ON")
        }else{
            defaults.setBool(false, forKey: "SoundActive")
            print("Sound OFF")
        }
    }

Currently, the actual default value is initially false when the user first launches the application.

How can I implement the defaults to be true if the user launches the app and they haven't been configured yet.

I've seen methods in Objective-C, but nothing in Swift. From what I've seen you can do it in the app delegate somehow, or in a PList file. How do I do either of those ones?

Menaim
  • 937
  • 7
  • 28
Big Green Alligator
  • 1,175
  • 3
  • 17
  • 33

10 Answers10

79

Swift 3 syntax example

Register a boolean default value:

UserDefaults.standard.register(defaults: ["SoundActive" : true])

And to get the value:

UserDefaults.standard.bool(forKey: "SoundActive")

Sidenote: Although the above code will return true, note that the value isn't actually written to disk until you set it:

UserDefaults.standard.set(true, forKey: "SoundActive")
Novi
  • 840
  • 7
  • 5
  • 1
    What do you mean by `the value isn't actually written to disk until you set it`? Does this mean that, should I never set the default and remove the registration from the `AppDelegate` in future versions, the key wouldn't retrieve `true` because it was never manually set? – TomQDRS Apr 01 '19 at 14:20
  • 1
    @TomQDDRS that's correct. Quoting https://developer.apple.com/documentation/foundation/nsuserdefaults/1417065-registerdefaults?language=objc: "The contents of the registration domain are not written to disk; you need to call this method each time your application starts." – Fabian Streitel Jul 08 '19 at 11:18
29

Add this to your didFinishLaunchingWithOptions method from the AppDelegate. As some others pointed out try not to abuse by putting everything in this method.

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    /// Here you can give default values to your UserDefault keys
    UserDefaults.standard.register(defaults: [
        "SoundActive": true,
        "someOtherKey": "Some Message"
        ])
}
fs_tigre
  • 10,650
  • 13
  • 73
  • 146
18

Swift 4

I prefer to implement a function similar to UserDefaults.string(forKey: ) which returns nil if the value is not set. Combined with the ?? operator, you don't need to have any default values written to disk unless you explicitly set them later.

extension UserDefaults {

    public func optionalInt(forKey defaultName: String) -> Int? {
        let defaults = self
        if let value = defaults.value(forKey: defaultName) {
            return value as? Int
        }
        return nil
    }

    public func optionalBool(forKey defaultName: String) -> Bool? {
        let defaults = self
        if let value = defaults.value(forKey: defaultName) {
            return value as? Bool
        }
        return nil
    }
}

Then you can retrieve your default values as follows

let defaults = UserDefaults.standard
let userName = defaults.string(forKey: "Username") ?? "Happy"
let userAge = defaults.optionalInt(forKey: "Age") ?? 21
let isSmart = defaults.optionalBool(forKey: "Smart") ?? true
ataravati
  • 8,891
  • 9
  • 57
  • 89
Guy Brooker
  • 726
  • 7
  • 11
9

Using "registerDefaults" you can set Default value of NSUserDefaults

let userDefaultsDefaults = [
            "SoundActive" : true
        ]

NSUserDefaults.standardUserDefaults().registerDefaults(userDefaultsDefaults)

Note: write this in didFinishLaunchingWithOptions, so default value is set.

write below code where you want to check

 let onoroff = NSUserDefaults.standardUserDefaults().objectForKey("SoundActive") as! Bool!

 if (onoroff != nil && onoroff == false)
 {
    self.checkForAgreement()
 }
Hardik Thakkar
  • 15,269
  • 2
  • 94
  • 81
5

There is nothing swift or app delegate specific.

Initial defaults are set by calling registerDefaults: on the standardUserDefaults instance.

You can make this call multiple times and I'd recommend that you don't do it in the app delegate, instead register appropriate details at appropriate times in the app, so if you have 1 view controller / subsystem which uses certain defaults values then register the default values as part of the initialisation if that code.

Only if you have something which is used by multiple different parts of the code should you consider doing that in the app delegate, and then only if you don't have some other appropriate controller in which to do it.

Wain
  • 118,658
  • 15
  • 128
  • 151
  • Why would't you do it in the app delegate? – Daniel Jun 15 '16 at 09:16
  • 1
    because the app delegate is there for a specific purpose, and arbitrary user defaults registration is not part of that purpose @simpleBob - being the delegate of the application and handling application level events is, nothing else – Wain Jun 15 '16 at 09:19
  • 3
    But user defaults registration should be done before anything else, that's why `didFinishLaunchingWithOptions` would be a rather obvious place and it is where it is found in most projects. Also, I think it is better to have all defaults in one place than having multiple `registerDefaults` across the whole project. – Daniel Jun 15 '16 at 10:15
  • it should be done before it is required, and it should be done in a sensible place. sure you can do it in the app delegate, but that is not the purpose of the app delegate, it's just easy and that's why most people do it. @simpleBob – Wain Jun 15 '16 at 10:17
  • 1
    I think the problem of registering the default when you need them is that someone may need it even earlier and forget to move the registering. – Daniel Jun 15 '16 at 10:26
4
func lastStatus() -> Bool {
    let defaultValue = true
    if let value = default.valueForKey("SoundActive") {
        // then use it
        return value as? Bool ?? defaultValue
    } else {
        // oh, no value?
        return defaultValue
    }
}

I think this is best way of using it. Also register(defaults:) will help, but in documentation Apple suggest to using it as fallback, like separating situation of no value and default value. Depend on your need.

Klein Mioke
  • 1,261
  • 2
  • 14
  • 23
4

You can encapsulate all of your UserDefaults logic into a property variable that automatically registers the application default and saves any updates back into the user defaults dictionary. This is especially convenient if other parts of the app (besides the switch control) also read or change this state.

Swift 5 — The first part executes a closure to initialize the property, and the second part is the didSet block which is called automatically any time the property is changed.

var soundIsActive: Bool = {
        // Register the app default:
        UserDefaults.standard.register(defaults: ["SoundActive" : true])

        // Initialize the property with the current user default:
        return UserDefaults.standard.bool(forKey: "SoundActive")
    }()
    {
        didSet {
            // Update user default when the variable is set:
            UserDefaults.standard.set(soundIsActive, forKey: "SoundActive")
        }
    }
Robin Stewart
  • 3,147
  • 20
  • 29
0

If you really want to do it this way, put this in the AppDelegate:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    let defaults = NSUserDefaults.standardUserDefaults()
    if defaults.valueForKey("SoundActive") == nil {
        defaults.setBool(true, forKey: "SoundActive")
    }

If it is just used in the one viewcontroller, consider putting the code in the viewDidLoad method instead!

Dominic
  • 258
  • 2
  • 8
  • I don't think it's a good way, because every time I launched the app, it would run these codes. But in fact, it's only needed at first time. – Klein Mioke Jun 15 '16 at 09:03
  • OK, you edit it. But I think the best place is when you use the value of "SoundActive", if nil then true. – Klein Mioke Jun 15 '16 at 09:06
0

Generic version of how to set a default value:

enum UserDefaultsKeys: String {
    case username = "kUsername"
}

extension UserDefaults {
    func optionalValue<T>(forKey key: UserDefaultsKeys) -> T? {
        if let value = self.value(forKey: key.rawValue) {
            return value as? T
        }
        return nil
    }
}

let username = defaults.optionalValue(forKey: .username) ?? ""
Pavel Bogart
  • 405
  • 5
  • 16
-1

Put this in your "didFinishLaunchingWithOptions" in your AppDelegate.

if defaults.valueForKey("launchedAlready") == true {
       print("Not first launch.")
    }
    else {
       defaults.setValue(true, forKey: "launchedAlready")
        defaults.setBool(true, forKey: "SoundActive")
        print("Sound ON")
    }
AMAN77
  • 6,218
  • 9
  • 45
  • 60