【问题标题】:Best way to initialize non-optional var if optional is nil in Swift如果可选在 Swift 中为 nil,则初始化非可选 var 的最佳方法
【发布时间】:2017-10-25 14:33:08
【问题描述】:

我想通过从UserDefaults 中获取变量obj 来初始化它,它返回一个String?,如果是nil,则构建值并分配它。

以下代码有效,但最后,我的obj 是String?,而我希望它是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?

这种情况有没有好的模式/最佳实践?

【问题讨论】:

标签: swift optional


【解决方案1】:

您可以将 nil-coalescing 运算符 ?? 与 “立即评估关闭”:

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`

如果未设置用户默认值,则执行闭包。 闭包创建并设置用户默认值(使用 local obj 变量)并将其返回给调用者,这样 它被分配给外部obj 变量。

【讨论】:

  • 简洁的方法。 :) +1
【解决方案2】:

可选绑定。你可以阅读它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)

【讨论】:

  • 你甚至可以let obj: String
【解决方案3】:

使用guard let 或if let。

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

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)
} 

(!)另外,真的不用再打电话给defaults.synchronize()了:

等待对默认数据库的任何挂起的异步更新 并返回;这种方法是不必要的,不应该使用。

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

【讨论】:

  • if let 示例不起作用,因为您尝试将值分配给 obj 这是一个 let 常量。此外,它会尝试覆盖从 UserDefaults 返回的值,这与请求的值相反
  • 你是对的。不够细心。会更正。
【解决方案4】:

您还可以使用隐式展开的可选选项,如下所示:

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`

【讨论】:

    猜你喜欢
    • 2016-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-30
    • 2014-12-29
    • 1970-01-01
    • 2020-02-26
    • 2020-08-29
    相关资源
    最近更新 更多