Swift 可选属性声明之间的区别 [重复]

Posted

技术标签:

【中文标题】Swift 可选属性声明之间的区别 [重复]【英文标题】:The difference between Swift Optional Property Declarations [duplicate] 【发布时间】:2018-05-15 07:53:17 【问题描述】:

我注意到 Swift 的一些编码示例以不同的方式声明可选属性。但是,我似乎很难区分它们(或者更确切地说,何时使用它们。)

class MyClass 
   // I believe this can start as nil but should always be set
   // once it is.
   var optionalProperty1: Type!

   // I believe this can be set or nil anytime.
   var optionalProperty2: Type?

   // I think this is the same as
   // var optionalProperty3: Type!
   lazy var optionalProperty3: Type

每一种与其他的有何不同?何时应该使用每一种?

【问题讨论】:

【参考方案1】:

var optionalProperty1: Type!

当您确定您将拥有此属性的价值时,例如timestamp,这将是肯定的。是的,它也可以是nil

var optionalProperty2: Type?

如果您不确定该值(或者此字段不是必需的),请将其作为 optional 例如:- 如果我创建一个 Personaddress 可以是 optionalname不会。

lazy var optionalProperty3: Type

此语法错误,您不能以这种方式声明lazy 属性。您必须最初为它分配一些东西。见下例:

/// First way
lazy var optionalProperty3: String = 
    return "Hello"
()

/// Second way
lazy var optionalProperty4 = "Hello"

lazy 存储属性是一个属性,其初始值在第一次使用之前不会计算。您可以通过在声明之前编写惰性修饰符来指示 lazy 存储属性。 lazy 变量非常适合需要设置一次,然后永远不会重新设置的东西。

在现代Swift 中确实不需要指定类型的另一件事。表示如果你分配0,它本身就是一个整数,如果你分配0.0,它将把它当作double,对于StringArray等也是一样。

【讨论】:

我认为 1 和 2 分别用于当您希望在值为 nil 时崩溃以及当您希望应用程序在值为 nil 时继续运行时。选项的主要用途是跟踪错误并确定哪些值需要有效才能使应用程序继续处于有效状态。这类似于将函数调用放在 try-catch 中,并让调用方法进一步抛出的区别。 var optionalProperty1: Type! 也可以是nil 也可以查看if optionalProperty1 == nil。尽管有几种想法可以从 optional 属性中获得好处。【参考方案2】:

第三个声明不是可选的。

第三个声明了一个惰性属性。惰性属性仅在首次使用时才会被初始化。示例:

class A 
    lazy var a: Int = 
        print("hello")
        return 1 + 1
    ()


let a = A()
print(a.a)

如果你删除最后一行,hello 将不会被打印出来。

第一个声明是隐式解包的可选项,而第二个声明是普通的可选项。

当您访问普通可选项的成员时,您需要使用?! 将其解包:

var myInt: Int? = ...
print(myInt.description) // doesn't compile, must unwrap
print(myInt!.description) // will crash if myInt is nil
print(myInt?.description) // will print "nil" if myInt is nil

另一方面,隐式解包的选项会隐式执行此操作 - 每当您尝试访问成员时,它都会使用 ! 为您隐式解包:

var myInt: Int! = ...
print(myInt.description) // equivalent to "myInt!.description"

【讨论】:

【参考方案3】:

来自 Apple 的 Swift 文档:

Optionals (?):“在值可能不存在的情况下使用可选值。可选值代表两种可能性:要么存在值,您可以打开可选值以访问该值,或者不存在完全有价值。”

Implicitly Unwrapped Optionals (!):“如上所述,可选项表示允许常量或变量“无值”。可使用 if 语句检查可选项以查看值是否存在,并且可以有条件地使用可选绑定展开以访问可选值(如果它确实存在)。

有时,从程序的结构中可以清楚地看出,在第一次设置该值之后,可选项总是有一个值。在这些情况下,不必在每次访问可选值时检查和解包它的值,因为可以安全地假定它始终都有一个值。

这些类型的选项被定义为隐式展开的选项。通过在要设为可选的类型之后放置感叹号(字符串!)而不是问号(字符串?)来编写隐式展开的可选。

当一个可选项的值在第一次定义后立即确认存在并且可以肯定地假定在此后的每个点都存在时,隐式展开的可选项很有用。 Swift 中隐式解包的可选项的主要用途是在类初始化期间,如无主引用和隐式解包的可选属性中所述。"

阅读更多https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html

【讨论】:

【参考方案4】:

显式解包变量

var optionalProperty1: Type!

这意味着该值永远不应为零。它将始终被初始化,但最好使用var optionalProperty1: Type

可选

var optionalProperty2: Type?

这是一个可选值,这意味着它可以有一个值或为零。通常使用您需要打开它的值。使用条件展开或保护语句...

if let value = optionalProperty2 
    print("optionalProperty2 had a value, value is set")


guard let value = optionalProperty2 else 
   print("optionalProperty2 was nil value is nil") 

或者你可以只检查它是否有一个值并显式打开它(这不是最佳实践)

if optionalProperty2 != nil 
    print("optionalProperty2 is set to \(optionalProperty2!)")

惰性变量

lazy var optionalProperty3: Type 一个惰性变量是不同的,它不是可选的,除非你定义它是可选的。在第一次使用该值之前,惰性变量不会初始化为该值。因此,如果您不调用/使用该变量,它将永远不会被设置。

【讨论】:

以上是关于Swift 可选属性声明之间的区别 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

Swift 中的可选闭包属性

Swift中 !和 ?的区别及使用

无法在 swift 中将常量声明为可选?

具有标量类型的 Swift Core Data 可选属性被评估为 0 而不是 NIL [重复]

如何在 Swift 上为堆栈声明“如果可选”

Swift学习笔记————可选类型(Optional Type)