我已阅读this个问题以及其他一些问题。但它们与我的问题
有点无关对于UILabel
,如果您未指定?
或!
,则会出现以下错误:
@IBOutlet属性具有非可选类型'UILabel'
然后Xcode为您提供 2 选项以便修复它,您可以这样做:
修复它添加?形成可选类型UIlabel?
修复它添加!来形成 隐式解包的可选类型UIlabel?
但是对于字符串,您只需输入string
?
或!
,就不会出现错误为什么会这样?
如果未设置name
会怎样?那么我们会nil
没有使用?
,!
和 Swift 来满足'类型安全'吗?
示例:
struct PancakeHouse {
let name: String // this doesn't have '?' nor '!'
let photo: UIImage?
let location: CLLocationCoordinate2D?
let details: String
}
我主要的疑惑是我们什么时候想不使用Optional?
答案 0 :(得分:8)
文档中涵盖了所有这些:The Swift Programming Language - The Basics。
简而言之:
String
表示保证存在的String
。这个值无法为零,因此直接使用是安全的。
String?
代表Optional<String>
,可以是nil
。您无法直接使用它,必须首先打开它(使用guard
,if let
或强制解包运算符!
)以生成String
。只要您不强行用!
打开它,这也是安全的。
String!
也代表Optional<String>
,可以是nil
。但是,此选项可用于需要非选项的情况,这会导致隐式强制解包。这就像拥有String?
并且总是被!
隐式强制解包。这些都很危险,因为nil
的出现会导致程序崩溃(除非您手动检查nil
)。
答案 1 :(得分:6)
对于PancakeHouse
结构,name
是非可选的。这意味着它的name
属性不能为零。编译器将强制执行name
初始化PancakeHouse
实例时初始化为非零值的要求。它通过要求在为name
定义的任何和所有初始化程序中设置PancakeHouse
来实现此目的。
对于@IBOutlet
属性,这是不可能的。取消归档/加载Interface Builder文件(XIB或Storyboard)时,会设置IB文件中定义的出口,但在其中的对象初始化之后(例如在视图加载期间),总是会出现。因此,在初始化之后但是在设置插座之前必须有一段时间,并且在此期间,插座将是零。 (还有一个问题是出口可能没有在IB文件中设置,并且编译器没有/不能检查它。)这解释了为什么@IBOutlet
属性必须是可选的
隐式解包的可选(!
)和?
的常规可选(@IBOutlet
)之间的选择取决于您。参数本质上是使用!
允许您将属性视为非可选属性,因此永远不会为零。如果由于某种原因它们是零,那通常被认为是程序员错误(例如插座没有连接,或者你在查看加载完成之前访问它等等),在那些情况下,在开发过程中因崩溃而失败将有助于你抓住这个bug更快。另一方面,将它们声明为常规选项,需要使用任何代码来明确处理由于某种原因可能未设置它们的情况。 Apple默认选择隐式解包,但有些Swift程序员出于自己的原因,使用@IBOutlet
属性的常规选项。
答案 2 :(得分:1)
整个&#34;可选&#34;一开始我的事情很糟糕。是什么让它&#34;点击&#34;对我来说,当我不再把它们想象成&#34; String&#34;对象并开始将它们视为泛型。就像&#34; Array&#34;具有&#34; String&#34;的通用标识符;是一个数组,如果它有值,则包含字符串......&#34;字符串?&#34;是一个可选项,如果它有一个值,则是一个字符串。
String - 这总是保证是某种字符串,并且永远不会。声明变量时,必须为其赋值。
的字符串? - 这是一个可选项。它可以是nil,如果它有一个值,它将是一个字符串。要访问可选的值,您必须打开它。
的字符串! - 这是一个可选的,带有语法糖,可以让你直接访问它的值,就像它只是一个字符串一样。它可能是零,但无论出于何种原因,变量周围的背景都向你眨了眨眼,并且说“不要担心,它会有价值。”#34;
答案 3 :(得分:0)
感谢Andrew Madsen的回答和所有其他答案,我自己学到了一点:
struct pairOfOptionalAndNonOptionalAndImplicitUnwrapped{
var word1 :String?
var word2 :String
var word3: String!
init (a:String, b: String, c: String){
self.word1 = a // Line A
self.word2 = b // Line B
self.word3 = c // Line C
} //Line BBBB
func equal() ->Bool{
return word1 == word2 + word3
}
}
let wordParts = pairOfOptionalAndNonOptionalAndImplicitUnwrapped (a:"partTwo", b: "part", c:"Two")
wordParts.equal() // Line CCCC
Return from initializer without initializing all stored properties
,我知道这是因为我已将属性word2
声明为非可选。我告诉编译器我保证让你设置...... Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_1386_INVOP, subcode=0x0)
当且仅当我运行wordParts.equal()
时,因为我告诉我的代码,这是一个可选的含义,它将在其他地方之后设置 / em>实例化/编译。这意味着如果你没有设置lldb可以通过我运行时错误。 (错误将发生在CCCC线上)