- 说明:
- 文中提到的”构造器”和Object_C中的”初始化”类似.
- 博文中的代码仅为讲解知识, 没有成型的项目Demo.
- 资料链接Swift2.0(中文版)
- 举例: (构造过程–默认构造器) 代表前面的文字出自”构造过程”这章中的”默认构造器”小节.
- 建议看一看Swift2.0中的(基础部分– 可选, nil, if语句以及强制解析, 可选绑定, 隐私解析可选类型) 和 (构造过程–存储属性的初始赋值, 默认构造器, 类的继承和构造过程)
- 此文章由 @春雨 编写. 经 @Scott 审核. 若转载此文章,请注明出处和作者
代码
class ViewController: UIViewController {
var titleString: String /**< 这样写属性, 编译器会报错: Class 'ViewController' has no initializers. */
}
原因:
- 一个类的所有存储属性(包括从父类继承来的任何属性)必须在构造过程中设置初始值.(构造过程–类的继承和构造过程)
如果结构体或类的所有属性都有默认值,同时没有自定义的构造器,那么 Swift 会给这些结构体或类提供一个默认构造器(default initializers)。这个默认构造器将简单地创建一个所有属性值都设置为默认值的实例.(构造过程–默认构造器)
综上所述, 由于titleString属性没有默认值, ViewController这个类的默认构造器就不能在构造过程中为titleString设置初始值, 所以编译器报错.
解决方案:
- 方案一: 为属性设置默认值.
- 方案二: 将属性设置为可选类型.
- 方案三: 将属性设置为隐式解包可选类型.
方案一: 为属性设置默认值.
class ViewController: UIViewController {
// 为存储属性设置默认值, 此时属性类型为: String类型.
var titleString: String = "Today"
}
方案二: 将属性设置为可选类型.
class ViewController: UIViewController {
// 在String后面加上?, 此时属性的类型为: Optional String类型.
var titleString: String?
}
- 解释:
- 在类型名后面加?, 这个类型就变成可选类型(例如: Int? 代表 Optional Int 类型, 而不是 Int类型.)
- 声明一个可选类型的常量或者变量, 但没有赋值时, 它们会自动被设置为nil.(基础部分–nil)
! 强制解包
注: 解包也叫解析. 这是翻译问题.
代码
class ViewController: UIViewController {
var titleString: String?
override func viewDidLoad() {
super.viewDidLoad()
titleString = "Hello"
let appendString = titleString + " World!" /*< 编译器报错: Value of optional type 'String?' not unwrapped; did you mean to use '!' or '?'? **/
}
}
原因
- 必须通过!对可选类型进行强制解析, 得到一个确定类型的值.
- 只能对两个String类型进行拼接, 不能对String和Optional String类型进行拼接.
举例:
titleString = "Hello"
let unwrappString = titleString!
print(unwrappString)
// 输出: Hello
let noUnwrappingValue = titleString
print(noUnwrappingValue)
// 输出: Optional("Hello")
- Swift语言可以进行类型推断.
- 从输出可以看出: unwrappingValue是String类型; noUnwrappingValue是Optional String类型.
- 可以按住option键, 将鼠标放到代码”unwrappingValue”上, 按鼠标左键, 在弹出的对话框中可以看到 let unwrappString: String , 也可以看出unwrappingValue是String类型.
解决方案
class ViewController: UIViewController {
var titleString: String?
override func viewDidLoad() {
super.viewDidLoad()
titleString = "Hello"
let appendString = titleString! + " World!" /**< 对titleString进行强制解包. */
}
}
- 注意:
如果没有titleString = “Hello”这行代码, 那么titleString的值就是nil, 对一个值为nil的可选类型强制解包, 在运行时程序会crash.
方案三: 将属性设置为隐式解包可选类型.
class ViewController: UIViewController {
// 在类型名后面加 !, 此时titleString就是隐式解包可选类型, 不是String类型, 也不是Optional String类型.
var titleString: String!
override func viewDidLoad() {
super.viewDidLoad()
}
}
- 这种类型在未明确赋值前, 默认为nil, 和可选类型相同.
隐式解包可选类型和可选类型的区别
代码
class ViewController: UIViewController {
var titleString: String!
var optionalString: String?
override func viewDidLoad() {
super.viewDidLoad()
titleString = "Hello "
optionalString = "Good "
let titleAppendString = titleString + "World"
let optionalAppendString = optionalString! + "Morning"
}
}
原因
我们可以观察到titleString在拼接”World”字符串时没有用!进行强制解包, 而optionalString必须使用!强制解包之后才可以拼接”Morning”.
这是因为对于隐式解包可选类型来说, 既有可选类型的特点, 又不用每次使用的时候都要用!进行强制解析. 也就是说在使用隐式解包可选类型的属性时, 编译器会自动解包, 不需要我们程序员自己添加!, 手动解包.
想要将属性设置成隐式解包可选类型的前提是: 确保在使用这个属性的时候, 这个属性的值不能是nil. 前面提到过, 对值为nil的可选类型进行解包, 在运行时会造成程序crash.
总结
- 在类型名后面加?代表可选类型, 例: String?
可选类型有两个值:
- 有值, 当可选类型有值时, 对可选类型进行解包出来的值的类型就是?前面的类型.
- 没有值, 当可选类型没有值时, 它的值为nil.
nil的详细内容请查看基础部分–nil! 有两个作用:
- 在变量名后面的 ! 代表强制解包.
- 在类型名后面的 ! 代表隐式解包可选类型.
当你确定存储属性有一个确定值或者直接给存储属性附一个默认值时, 可以选择方案一.
例:
class ViewController: UIViewController {
var isTrue: Bool = true
let number = 2
var textLabel: UILabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
}
}
在存储属性没有默认值的情况下, 如果这个属性在第一次赋值之后, 你确定它会一直有值, 不会出现nil这种情况, 那么将这个存储属性设置为隐式解包可选类型会比设置成可选类型好的多, 反之要设置成可选类型.
本文介绍了Swift中可选类型Optionals的概念及其重要性。当类的存储属性没有默认值时,编译器会报错。为解决此问题,提出了三种方案:设置属性默认值、将属性设为可选类型或隐式解包可选类型。文章详细讨论了可选类型的使用、强制解包以及隐式解包可选类型与普通可选类型的区别,并提供了代码示例进行说明。
4928

被折叠的 条评论
为什么被折叠?



