简体   繁体   English

在Swift中,如果optional是nil,则初始化非可选var的最佳方法

[英]Best way to initialize non-optional var if optional is nil in Swift

I would like to initialize a variable obj by taking it from UserDefaults , which returns a String? 我想从UserDefaults获取变量obj ,它返回一个String? , and if it's nil build the value and assign it. ,如果它是nil构建值并分配它。

The following code works, but, at the end, my obj is a String? 以下代码有效,但最后,我的obj是一个String? while I want it to be a String (since it can't be nil at this stage). 虽然我希望它是一个String (因为它在这个阶段不能nil )。

var obj = UserDefaults.standard.string(forKey: "my_key")// Here, obj is a String?
if obj == nil {
    obj =  ProcessInfo.processInfo.globallyUniqueString// Returns, a String
    defaults.set(obj, forKey: "my_key")
    defaults.synchronize()
}
// Here, obj is still a String?

Is there a good pattern / best practice for this kind of situation ? 对于这种情况,是否有良好的模式/最佳实践?

You can use the nil-coalescing operator ?? 你可以使用nil-coalescing运算符?? with an "immediately evaluated closure": “立即评估关闭”:

let obj = UserDefaults.standard.string(forKey: "my_key") ?? {
    let obj = ProcessInfo.processInfo.globallyUniqueString
    UserDefaults.standard.set(obj, forKey: "my_key")
    return obj
}()

print(obj) // Type is `String`

If the user default is not set, the closure is executed. 如果未设置用户缺省值,则执行闭包。 The closure creates and sets the user default (using a local obj variable) and returns it to the caller, so that it is assigned to the outer obj variable. 闭包创建并设置用户默认值(使用本地 obj变量)并将其返回给调用者,以便将其分配给外部obj变量。

Optional Binding. 可选绑定。 You can read up on it here 你可以在这里阅读

let obj: String

if let string = UserDefaults.standard.string(forKey: "my_key") {
    obj = string
} else {
    obj = ProcessInfo.processInfo.globallyUniqueString
    UserDefaults.standard.set(obj, forKey: "my_key")
}

print(obj)

Use either guard let or if let . 使用guard let或者if let

1) guard let (not common for your case, though) 1) guard let (虽然你的情况不常见)

guard let obj = UserDefaults.standard.string(forKey: "my_key") else { 
    // guard failed - obj is nil; perform something and return
    obj =  ProcessInfo.processInfo.globallyUniqueString
    defaults.set(obj, forKey: "my_key")
    return 
}

// obj is not nil, you have it at your disposal
print(obj)

2) if let 2) if let

if let obj = UserDefaults.standard.string(forKey: "my_key") {
   // obj exists
} else {
    let obj =  ProcessInfo.processInfo.globallyUniqueString
    defaults.set(obj, forKey: "my_key")
    print(obj)
} 

(!) Also, there really is no more need to call defaults.synchronize() : (!)此外,确实不再需要调用defaults.synchronize()

Waits for any pending asynchronous updates to the defaults database and returns; 等待默认数据库的任何挂起的异步更新并返回; this method is unnecessary and shouldn't be used. 此方法是不必要的,不应使用。

https://developer.apple.com/documentation/foundation/nsuserdefaults/1414005-synchronize https://developer.apple.com/documentation/foundation/nsuserdefaults/1414005-synchronize

You can also use an implicitly unwrapped optional, like this: 您还可以使用隐式解包的可选项,如下所示:

var obj: String! = UserDefaults.standard.string(forKey: "my_key")// Here, obj is a (possibly `nil`) `String!`
if obj == nil {
    obj =  ProcessInfo.processInfo.globallyUniqueString // Returns, a String
    defaults.set(obj, forKey: "my_key")
    defaults.synchronize()
}

// Here, obj is a non-`nil` `String!`, which will work the same as a `String`

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM