User Defaults - Store user data locally - swift 5 Xcode 11

User Defaults - Store user data locally - swift 5 Xcode 11

Apps need to store data. One of the easiest ways to store data locally is with user defaults. In this article, we will cover what user defaults are, how to use them, and why to use them. I follow Apple's documentation closely in this article, often quoting directly, so if you'd like to first look through their documentation follow the link at the bottom of the article.

"User defaults are an interface to the user’s defaults database, where you store key-value pairs persistently across launches of your app."

According to Apple, the defaults system allows an app to customize its behavior to match a user’s preferences. For example, you can allow users to specify their preferred units of measurement or media playback speed. Apps store these preferences by assigning values to a set of parameters in a user’s defaults database. The parameters are referred to as defaults because they’re commonly used to determine an app’s default state at startup or the way it acts by default.

class UserDefaults : NSObject

The user defaults are best used in small ways, but they can be quite vast. Before we continue defining and analyzing user defaults, let's quickly see how they work in a playground.

Go ahead and create a fresh playground so we can test how much and what types of data can be stored without distractions. Once created, open the identity tab and confirm that Playground Settings are set to macOS. This solves a common error where the playground never compiles or runs. Strange bug, but easy fix. You can open the tab by clicking the top right button on the tool bar. If your tool bar is missing, just hit Option-Command-T, or go to View -> Show Toolbar.

No alt text provided for this image

Delete all the code in the playground and replace it with import Foundation. We won't need to create any additional files or import other frameworks after this point.

import Foundation

Here is a quick example of user defaults in action before we jump back into Apple's documentation.

import Foundation

UserDefaults.standard.set(false, forKey: "User Defaults")
print(UserDefaults.standard.bool(forKey: "User Defaults")) //false
UserDefaults.standard.set(true, forKey: "User Defaults")

print(UserDefaults.standard.bool(forKey: "User Defaults")) //true

Line by line, we import foundation so we can access the included UserDefaults NSObject. Next we set the user defaults key "User Defaults" to a value of false. We request and print the value of a key "User Defaults" and it returns false (like we set). We repeat, however this time we set a value of true for the key "User Defaults" and when we print to console it now returns true.

Modify your code to only print the value of User Defaults:

import Foundation
 

print(UserDefaults.standard.bool(forKey: "User Defaults")) //true

The playground will remember the most recent default you set for "User Defaults", and output true. Switch the order from before in your playground and run again. This time it will output true first and false second.

import Foundation

UserDefaults.standard.set(true, forKey: "User Defaults")
print(UserDefaults.standard.bool(forKey: "User Defaults")) //true
UserDefaults.standard.set(false, forKey: "User Defaults")

print(UserDefaults.standard.bool(forKey: "User Defaults")) //false

Once again, modify your code to only print the value of User Defaults:

import Foundation
 
print(UserDefaults.standard.bool(forKey: "User Defaults")) //false

This time the playground will output false. Since we switched the order of our code, it sets the default to false last, which the playground remembers as our most recent default.

According to Apple, at runtime, you use UserDefaults objects to read the defaults that your app uses from a user’s defaults database. UserDefaults caches the information to avoid having to open the user’s defaults database each time you need a default value. When you set a default value, it’s changed synchronously within your process, and asynchronously to persistent storage and other processes.

User’s defaults are stored locally on a single device, and persisted*, for backup and restore. To synchronize preferences and other data across a user’s connected devices, use NSUbiquitousKeyValueStore instead.

*Persistence refers to the characteristic of state that outlives the process that created it. If you are not familiar, I highly suggest reading this wikipedia article. htps://en.wikipedia.org/wiki/Persistence_(computer_science)

NSUbiquitousKeyValueStore uses the iCloud key-value store to make preference, configuration, and app-state data available to every instance of your app on every device connected to a user’s iCloud account. You can store scalar values such as BOOL, as well as values containing any of the property list object types: NSNumber, NSString, NSDate, NSData, NSArray, and NSDictionary. It requires connection to iCloud unlike UserDefaults.

You can apply the majority of what we discuss in regards to UserDefaults to NSUbiquitousKeyValueStore. When considering using these NSObjects keep in mind how a user will use the app. It is usually safe to use UserDefaults, but NSUbiquitousKeyValueStore could cause issues if you are not careful.

A default object must be a property list.

The UserDefaults class provides convenience methods for accessing common types such as floats, doubles, integers, Boolean values, and URLs. You can store any object that is a property list (NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary). If you want to store any other type of object, you should typically archive it to create an instance of NSData. Earlier we stored a Boolean value with a convenience method.

If you are working with files and you store the file location for a particular file and the user moves that file, your app may not be able to locate that file on next launch. To avoid this issue, first find the file by its system identity, and store the system identity as a key. You can then use the URLByResolvingBookmarkData method to resolve the bookmark data stored in user defaults to a file URL.

func set(Any?, forKey: String)
//Sets the value of the specified default key.

func set(Float, forKey: String)
//Sets the value of the specified default key to the specified float value.

func set(Double, forKey: String)
//Sets the value of the specified default key to the double value.

func set(Int, forKey: String)
//Sets the value of the specified default key to the specified integer value.

func set(Bool, forKey: String)
//Sets the value of the specified default key to the specified Boolean value.

func set(URL?, forKey: String)

//Sets the value of the specified default key to the specified URL.

Note that values returned from UserDefaults are immutable, even if you set a mutable object as the value. For example, if you set a mutable string as the value for “MyStringDefault”, the string you later retrieve using the string(forKey: )method will be immutable. If you set a mutable string as a default value and later mutate the string, the default value won’t reflect the mutated string value unless you call set(_:forKey: ) again. In other words, to change the value, you must assign the value to a new variable and call the set method again with your new variable.

You can use key-value observing to be notified of any updates to a particular default value. You can also register as an observer for didChangeNotification on the default notification center in order to be notified of all updates to a local defaults database. I cover passing data throughout your app with notification center in the article below, but the article utilizes the name NotficationCenter database.

At this point we will return to our playground where we will test the limits of the defaults and try a few more value types. Let's try storing an array with 10000 values.

import Foundation

var strArray : Array<String> = []

for position in 0...10000{
    let str = "This is a string \(position)"
    strArray.append(str)
}

UserDefaults.standard.set(strArray, forKey: "User Defaults")

Now we will remove the set function and the loop and test to see if our code has successfully stored our data. This time quit Xcode entirely and when it relaunches replace your code with the following.

import Foundation


print(UserDefaults.standard.array(forKey: "User Defaults")!)

Even after closing our playground, the array of 10,000 string values was successfully stored and retrieved! If you look at our method, you will notice that comparatively from when we stored Booleans, we call UserDefaults.standard.array instead of UserDefaults.standard.bool.

UserDefaults.standard.object(forKey: "")
UserDefaults.standard.data(forKey: "")


UserDefaults.standard.string(forKey: "")


UserDefaults.standard.integer(forKey: "")
UserDefaults.standard.double(forKey: "")
UserDefaults.standard.float(forKey: "")


UserDefaults.standard.array(forKey: "")

UserDefaults.standard.dictionary(forKey: "")

Depending on the value of the key, you will need to call a different method, although calling the wrong data type will not cause a crash. In the following example, we set a value of 1 for the key "1".

import Foundation


UserDefaults.standard.set(1, forKey: "1")


print(
UserDefaults.standard.object(forKey: "1"),
UserDefaults.standard.data(forKey: "1"),


UserDefaults.standard.string(forKey: "1"),


UserDefaults.standard.integer(forKey: "1"),
UserDefaults.standard.double(forKey: "1"),
UserDefaults.standard.float(forKey: "1"),


UserDefaults.standard.array(forKey: "1"),
UserDefaults.standard.dictionary(forKey: "1")
)

//Optional(1) nil Optional("1") 1 1.0 1.0 nil nil

If you run the code, you will find that many of the methods return data even though our original value was simply 1. This should be extremely reassuring, but could be expected considering the care that Apple has taken to keep Swift safe.

At this point you should be able to handle most situations that come up with user defaults. We examined several data types and even brushed over the possibility of using NotificationCenter to listen for changes, so let's discuss some of the most common use cases.

Light and dark mode setting if you haven't yet converted your code to handle the new dark mode features in iOS 13. Keep signed in. Last logged in time. Private data that never touches the cloud. The last portion might be the most interesting in an age of consumer alarm about data and privacy.

In apps that I've written, I often use defaults to keep track of settings such as light and dark mode, and other choices about how the app should behave and look globally.

Apple Documentation:


要查看或添加评论,请登录

Ean Krenzin-Blank的更多文章

社区洞察

其他会员也浏览了