另外几个知识点: 熟练使用Swift中的区间、Swift枚举
本文的目的是做成一个手册,方便自己随时查看。

一、存储属性
/* 1. 存储属性
(0) 可以在类、结构体中使用,且初始化器调用完,所有成员必须有值。
(1)不能写set、get方法;写了会变成计算属性
(2)let和var的区别:let是第一次赋值之后不可变
*/
class ZLPropertyClass {
// 1.带初始值的存储属性
var name: String = "dd"
// 2.如果是可选类型,初始值是nil
var age: Int?
// 3.存储属性没有初始化值,且在初始化器中没有赋值,会报错
// var isMan: Bool
// 4.let类型的存储属性也是需要有初始值或者初始化器中赋值
let author2: String
// 5.let类型的存储属性内存也是在实例中的
let author = "dandy"
// 6. 设置闭包返回值为初始值时,闭包会在初始化器调用前调用
// let类型设置闭包返回值为初始值的
let testA: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
return formatter
}()
// var类型设置闭包返回值为初始值
var testB: DateFormatter = { DateFormatter() }()
// 初始化器,初始化器调用完,所有成员必须有值(或者是lazy、可选类型)
init() {
// 上面的author2没有初始值,在这里赋值也是一样的
author2 = "dandy2"
}
}
二、类型存储属性
/* 类型存储属性:
1.在类、结构体、枚举中可以定义,使用static修饰,不能用class修饰。
2.static修饰的变量默认是lazy类型的,必须要有初始值(初始值可以是闭包的返回值)。
3.类型存储属性本质是全局变量。
*/
class ZLTypePropertyClass {
// 使用static声明为类型存储属性
static var langugue: String = "Swift"
static let company: String = "Apply"
// 类型存储属性无论是let还是var类型都必须有初始值,不然会报错,而且在初始化器设置也没用的
// static var aa: Bool
// static let bb: Bool
// 不允许使用class来修饰存储属性
// class let cc = false
// class var dd = true
}
三、计算属性
/* 计算属性:
1.在类、结构体、枚举中可以定义, 只能用var修饰,本质上是一个方法。
2.可以有set、get方法,至少要有get方法。
3.子类可重写父类存储、计算属性为计算属性,不可重写为存储属性。
*/
class ZLComputePropertyClass: ZLPropertyClass {
var carName = "比亚迪·唐 C15"
// 1.有set和get方法的计算属性
var displayName1: String {
set { carName = newValue }
get { return "电汽车" }
}
// 2.只有get方法时可以不写set和get关键字
var displayName2: String {
if carName.contains(substring: "比亚迪·唐") {
return "比亚迪·唐"
}
return "其它"
}
// 3. 如果get方法中只有一行代码,那么可以省略return
var displayName3: String { "汽车" }
// 4. 子类只能重写var类型的存储属性, 且只能重写为计算属性,且必须有set和get两个方法
override var name: String {
set {}
get { "" }
}
}
四、类型计算属性
/* 类型计算属性:
1.在类、结构体、枚举中可以定义,用static修饰, 在类中也可使用class修饰。
2.在类中使用class修饰的计算属性,子类可重写为类型计算属性.
*/
class ZLTypeComputePropertyClass {
static var name = "比亚迪·唐 C15"
// 1.static修饰,有set和get方法的计算属性
static var displayName1: String {
set { name = newValue }
get { return "电汽车" }
}
// 2.class修饰,只有get方法时可以不写set和get关键字
class var displayName2: String {
if name.contains(substring: "比亚迪·唐") {
return "比亚迪·唐"
}
return "其它"
}
// 3. class修饰,如果get方法中只有一行代码,那么可以省略return
class var displayName3: String { "汽车" }
// 4. class修饰,有set和get方法的计算属性
class var displayNam4: String {
set { name = newValue }
get { "出租车" }
}
}
/* 子类重写父类的类型计算属性时,可读可写的权限不少于父类
*/
class ZLSubClass: ZLTypeComputePropertyClass {
// 1.重写父类的类型计算属性,也用class修饰,那么自己类的子类也可重写计算属性
override class var displayName3: String { "电动汽车" }
// 2.重写父类的类型计算属性,也可以用static修饰,但自己的子类不能再重写
// override static var displayName3: String { "电动汽车" }
// 3. 重写父类的类型计算属性,父类计算属性是get,那么可以有set和get,也可以只有get
// override class var displayName2: String { "特斯拉" }
override class var displayName2: String {
set {}
get { "特斯拉" }
}
// 4.重写父类的类型计算属性,父类计算属性是set + get, 子类必须也有set、get
override class var displayNam4: String {
set {}
get { "高级出租车" }
}
}
五、属性观察器
/* 属性观察器指的是willSet、didSet方法,可以通过他们来监听存储属性变化.
1.只可以对var类型添加属性观察器,并且计算属性\类型计算属性不能添加属性监听器.
2.添加属性观察器之后,对于存储属性,初始值及初始化器中的赋值都不会触发观察器;
对于类型存储属性来说,除初始值外的变化都会触发观察器。
3.willset的默认参数newvalue,didset的默认oldvalue.
4.本质上是在修改值之前和之后调用对应的willset\didset方法.
*/
class ZLPropertyListen {
/// 0. 计算属性看子类重写时设置属性监听器
var computeP: Int {
set { print("computeP.set") }
get {
print("computeP.get")
return 5
}
}
// 1.存储属性带初始值的观察:在初始化器调用完成后的值变化才会触发
var status = 0 {
willSet { print("status.willSet", newValue) }
didSet { print("status.didSet", oldValue) }
}
// 2.可选类型的观察:同1
var name: String? {
willSet { print("name.willSet",newValue) }
didSet { print("name.didSet",oldValue) }
}
// 3.带闭包返回值为初始值的属性观察器:同1
var dispalyName: String = { "红旗" }() {
willSet { print("dispalyName.willSet", newValue) }
didSet { print("dispalyName.didSet", oldValue) }
}
// 4.static类型存储属性设置观察器(class不能用来修饰存储属性):除初始值外的变化会触发
static var staticP = { DateFormatter() }() {
willSet { print("staticP.willSet", newValue) }
didSet { print("staticP.didSet", oldValue) }
}
// 这里面只有类型存储属性staticP的赋值会触发属性观察器
init() {
status = 999
name = "dandy"
dispalyName = "国产汽车"
Self.staticP = DateFormatter()
}
}
/* 子类重写父类的存储属性
1.如果重写为计算属性,那么不能再添加观察器
2.如果重写时添加观察器,那么不能再写set、get(即不能重写为计算属性)
3.子类重写父类的计算属性或类型计算属性时,可以不重写为计算属性,只添加属性观察器.
4.子类重写父类属性为计算属性时,不会触发父类的属性观察器.
5.子类初始化器中super.init()之后的赋值会触发子类和父类的属性观察器,调用顺序:
①重写时添加属性观察器:子类willSet->父类willSet->父类didSet->子类didSet
②重写父类计算属性时添加属性观察器:父类get->子类willSet->父类set->子类didSet
③子类初始化器中使用super.property来修改属性值时,只会触发父类的计算属性方法或父类属性监听器
*/
class ZLSubPropertyListen: ZLPropertyListen {
// 1.重写时设置监听器,不能再写set、get
override var status: Int {
willSet { print("子类status.willSet", newValue) }
didSet { print("子类status.didSet", oldValue) }
}
// 2.重写为计算属性,不能再设置监听器
override var name: String? {
set { print("子类name.set", newValue) }
get {
print("子类name.get", name)
return "流浪地球🌏"
}
}
// 3.重写父类的计算属性,但只添加属性观察器
override var computeP: Int {
willSet { print("子类computeP.willSet", newValue) }
didSet { print("子类computeP.didSet", oldValue) }
}
// 自身属性
var SubP = 100
// 子类初始化器中给父类属性赋值必须在super.init()之后,之前只能给自身类中属性赋值
// 在super.init()之后给父类的属性赋值会触发子类重写时添加的属性监听器然后触发父类的属性监听器
// 在super.init()之后如果用super.property来进行赋值,只会触发父类的计算属性方法或父类属性监听器
override init() {
SubP = 80
super.init()
status = 999
name = "dandy"
dispalyName = "国产汽车"
computeP = 666
super.status = 999
super.name = "dandy"
super.dispalyName = "国产汽车"
super.computeP = 666
}
}
六、Lazy属性
/* lazy属性
1.lazy可用来修饰var存储属性,类型存储属性let、var默认是lazy;不能用来修饰计算属性
2.本质上是在变量初始化时先将变量初始化为一个标识,后续真正使用时才初始化
3.类型存储属性默认就是lazy的,但也可以使用let修饰
4.多线程使用时需要注意,lazy并不保证线程安全
5.lazy属性初始值生成不会触发属性监听器
*/
class ZLLazyProperty {
// lazy属性是可选类型时,默认值可以是nil
lazy var aaa: Int? = nil
// 用lazy修饰之后,会先初始化为一个lazy标记,在实际用到时才会生成DateFormatter
lazy var dateFormatter = DateFormatter()
// 使用lazy修饰,闭包会在真实用到titleLabel时才调用
lazy var titleLabel: UILabel = {
print("titleLabel初始化值闭包调用---")
return UILabel()
}()
// 使用static修饰的类型存储属性,默认就是lazy,不需要用lazy修饰.
static let shared = ZLLazyProperty()
// 使用static修饰的类型存储属性,闭包会在实际用到时调用
static var shared2: ZLLazyProperty = {
print("shared2初始化值闭包调用---")
let shared2 = ZLLazyProperty()
// some init setting
return shared2
}()
}
七、全局变量、局部变量
/* 全局变量
1.不需要用static修饰, 必须要有初始值,默认是lazy的,不能用lazy修饰。
2.可以是计算属性或添加属性观察器,但不能与计算属性同时存在。
*/
var productName = "productName" {
willSet {}
didSet {}
}
let productName2 = "productName2"
var productName3: String {
set {}
get { "productName3" }
}
func testVar() {
/* 局部变量可以用lazy修饰,其余与全局变量一样 */
lazy var product = "product" {
willSet {}
didSet {}
}
let product2: String
var product3: String {
set {}
get { "product3" }
}
product2 = "product2"
print(product, product2, product3)
}
网友评论