Swift Develops Tips Series - Modifying User Defaults

Posted by social_experiment on Thu, 23 May 2019 19:46:17 +0200

Original link

text

Those who have developed iOS must have used UserDefaults to access data. User Defaults is very simple to use. Let's take access to user names and mailboxes as an example to explore the specific use of User Defaults.

Storage code

let username = "DerekCoder"
let email = "derekcoder@gmail.com"

let defaults = UserDefaults.standard
defaults.set(username, forKey: "username")
defaults.set(email, forKey: "email")

Read code

let defaults = UserDefaults.standard
let username = defaults.string(forKey: "username") // Type: String?
let email = defaults.string(forKey: "email") // Type: String?

Although the implementation is simple, there is a clear problem with the above code. We shouldn't knock the constants "username" and "email" every time we use them. It's easy to misspell or forget how to spell them. We should make full use of IDE's automatic completion function.

OK, let's improve the above code

let username = "DerekCoder"
let email = "derekcoder@gmail.com"

let KEY_FOR_USERNAME = "username"
let KEY_FOR_EMAIL = "email"

let defaults = UserDefaults.standard
defaults.set(username, forKey: KEY_FOR_USERNAME)
defaults.set(email, forKey: KEY_FOR_EMAIL)
let defaults = UserDefaults.standard
let username = defaults.string(forKey: KEY_FOR_USERNAME) // Type: String?
let email = defaults.string(forKey: KEY_FOR_EMAIL) // Type: String?

At this time, we have solved the problem of typing the wrong Key's name, but there is still a problem, that is, if we do not remember the constant name defined, of course, we can go to the constant file defined at this time to view, which will interrupt your current process, affect efficiency, and affect mood. Is there a way for the IDE to automatically prompt you for all User Default Keys that you currently define, and then we can just choose.

My solutions are as follows:

  • Add a new type UserDefaults.Name
extension UserDefaults {
    public struct Name: RawRepresentable, Equatable {
        public var rawValue: String
        
        
        public init(rawValue: String) {
            self.rawValue = rawValue
        }
        
        public init(_ rawValue: String) {
            self.rawValue = rawValue
        }
    }
}
  • Extend the UserDefaults.Name type to support direct string assignment
extension UserDefaults.Name: ExpressibleByStringLiteral {
    public typealias UnicodeScalarLiteralType = String
    public typealias ExtendedGraphemeClusterLiteralType = String
    
    public init(stringLiteral value: String) {
        self.rawValue = value
    }
    
    public init(unicodeScalarLiteral value: String) {
        self.init(stringLiteral: value)
    }
    
    public init(extendedGraphemeClusterLiteral value: String) {
        self.init(stringLiteral: value)
    }
}
  • Extend UserDefaults and add new methods to assign and read data
extension UserDefaults {
    public func object(forName name: UserDefaults.Name) -> Any? {
        return object(forKey: name.rawValue)
    }
    
    public func set(_ value: Any?, forName name: UserDefaults.Name) {
        set(value, forKey: name.rawValue)
    }
    
    public func string(forName name: UserDefaults.Name) -> String? {
        return string(forKey: name.rawValue)
    }
    // Some methods are omitted here.
    ...
}
  • Define your Key Constant
extension UserDefaults.Name {
    static let username: UserDefaults.Name = "username"
    static let email: UserDefaults.Name = "email"
}
  • Implementing your assignment and reading
let defaults = UserDefaults.standard
defaults.set(username, forName: .username)
defaults.set(email, forName: .email)

let username = defaults.string(forName: .username) // Type: String?
let email = defaults.string(forName: .email) // Type: String?

When you need to use the Key Constant in the last step of assignment and reading, you just need to hit a point first, and Xcode will show all the Key Constants of UserDefaults. You can choose the key you need. You don't have to be afraid of typing the wrong name or forgetting what the constant name is.


Screen Shot 2017-09-19 at 4.00.49 PM.png

Let's make an extension to support UserDefaults, and return a defaultValue if the corresponding Key value does not exist.

extension UserDefaults {
    public func string(forName name: UserDefaults.Name, defaultValue: String) -> String {
        return string(forKey: name.rawValue) ?? defaultValue
    }
}
let defaults = UserDefaults.standard
let username = defaults.string(forName: .username, defaultValue: "Unknown") // Type: String

summary

  • For the extension of UserDefaults, I omitted some methods to emphasize the point. See all the code, please refer to SwiftDevHints

Remarks

In the process of software development, in order to improve efficiency, it is very important to encapsulate the reused functions or modules. So I wrote an open source toolkit.- SwiftDevHints To summarize some small functions encapsulated in the actual project development process.

Just introduced is only one of the small features, want to see more features, please click directly SwiftDevHints . If you find it helpful, please give me a star.

Topics: iOS xcode