Reputation: 1185
I have a switch called soundSwitch
, I'm saving the state of the button using a 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?
Upvotes: 54
Views: 44638
Reputation: 2212
Use custom extension:
extension UserDefaults {
func value<T>(forKey key: String, defaultValue: T) -> T {
return object(forKey: key) as? T ?? defaultValue
}
}
and then usages:
UserDefaults.standard.value(forKey: "someKey", defaultValue: true)
or even more, you can use @propertyWrapper
@propertyWrapper
struct UserDefaultsBacked<T> {
let key: String
let defaultValue: T
var wrappedValue: T {
get {
return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
}
set {
UserDefaults.standard.set(newValue, forKey: key)
}
}
}
and usages:
@UserDefaultsBacked(key: Keys.someKey.rawValue, defaultValue: true)
var someValue: Bool
Upvotes: 0
Reputation: 744
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 key: String) -> Int? {
if let value = self.object(forKey: key) {
return value as? Int
}
return nil
}
public func optionalBool(forKey key: String) -> Bool? {
if let value = self.object(forKey: key) {
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
Upvotes: 20
Reputation: 3883
Swift 5 — You can encapsulate all of your UserDefaults
logic into a property 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.
This should either be a static property or used on a singleton preferences object, so that the initializer is only called once per app load. The first closure runs once when the object is initialized. The didSet
block automatically updates UserDefaults
any time the property is set.
static var soundIsActive: Bool = { // property initializer runs once
// 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")
}
}
Upvotes: 4
Reputation: 6302
Swift 5 Update
Set the boolean in your "didFinishLaunchingWithOptions" in your AppDelegate like so...
//Assumiing you have made a singleton for Userdefaults
public let defaults = UserDefaults.standard
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
defaults.set(true, forKey: "SoundActive")
//boiler plate code ...
}
Upvotes: -2
Reputation: 9703
Scalar types such as Bool, Int, Double will give a default value. To get an optional use object.
You can try this. Can also add a default value as in the second case below:
extension UserDefaults {
private enum Keys {
static let soundActiveOptional = "soundActiveOptional"
static let soundActiveDefaultTrue = "soundActiveDefaultTrue"
static let doubleValue = "doubleValue"
}
var soundActiveOptional: Bool? {
get {
return UserDefaults.standard.object(forKey: Keys.soundActiveOptional) as? Bool
}
set {
UserDefaults.standard.set(newValue, forKey: Keys.soundActiveOptional)
}
}
var soundActiveDefaultTrue: Bool {
get {
return UserDefaults.standard.object(forKey: Keys.soundActiveDefaultTrue) as? Bool ?? true
}
set {
UserDefaults.standard.set(newValue, forKey: Keys.soundActiveDefaultTrue)
}
}
var doubleValue: Double {
get {
return UserDefaults.standard.object(forKey: Keys.doubleValue) as? Double ?? 0.1
}
set {
UserDefaults.standard.set(newValue, forKey: Keys.doubleValue)
}
}
}
Upvotes: 1
Reputation: 445
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) ?? ""
Upvotes: 0
Reputation: 10738
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"
])
}
Upvotes: 35
Reputation: 1352
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.
Upvotes: 3
Reputation: 860
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")
Upvotes: 81
Reputation: 15951
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()
}
Upvotes: 9
Reputation: 258
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!
Upvotes: 0
Reputation: 119021
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.
Upvotes: 5