引言:上一章中我们介绍了类的初始化,以及属性,本章中我们将详细介绍类的属性、方法等
1.属性
属性可以划分为:存储属性、延迟加载属性、计算属性
(1)存储属性:可以分为常量存储属性(用let声明)、变量存储属性(用var声明)
用let声明属性时,后面都需要进行进行赋值,如:
class PersonInfo {
let name:String = "浩然"
}
如果不赋值,那么就会编译报错
注意:let声明属性在默认赋值之后,是无法在任何地方对该属性进行修改,若是修改则会编译报错
用var声明属性时,后面可以不需要进行赋值,但是需要后缀?或者!,这代表若此后该属性不赋值,默认为nil
如:var name:String?
在此插播讲解一下?、!的区别
本质上属性后面后缀?或!时,在不对其赋值时默认都为nil,如:
class PersonInfo {
var name:String?
var age:Int!
}
调用:let info = PersonInfo()
print("name=\(info.name),age:\(info.age)")
输出为:name=nil,age:nil
但是如果使用"?"声明的变量不赋值,直接调用对象的方法不执行,而使用"!"声明的变量不赋值,直接调用对象的方法运行会报错,如:
用"!"后缀属性
var label:UILabel!,定义一个label属性,继承自UILabel
不经过初始化,直接调用label.text = "浩然",此时编译会通过,但是运行以后触发该段代码时会崩溃。
因为此时系统默认你这个属性有值,但是其实该属性未经过初始化默认为nil,故导致崩溃
用"?"后缀属性
var label:UILabel?
不经过初始化,直接调用label?.text = "浩然",此时编译会通过,运行以后触发该段代码时不会崩溃,且不会执行。
因为在定义属性时后缀为nil,则在使用该属性时都会后缀?,运行该段代码时系统会先查询一下该属性是否有值,若为nil则不会执行该段代码,反之则会执行该段代码
使用总结;当你知道某个属性在调用它之前一定会被赋值,那么可以后缀!,反之则后缀?
(2)延迟加载属性:与OC里的懒加载很像,都是在用到它的时候完成赋值.注意延迟加载属性必须有默认赋值,且我们需要显式地指定属性类型
定义:在属性声明前使用 lazy 来标示一个延时加载存储属性,且该属性只能用var声明,如:
class ViewModel{
lazy var person = { (name:String,age:Int) -> PersonInfo in
let info = PersonInfo()
info.name = name
info.age = age
return info
}("浩然",3)
调用: let model = ViewModel()
print(model.person.name as Any)
输出为:Optional("浩然")
解析:1.person为声明继承哪个类,但是系统帮我们查找到了属于PersonInfo类
2.后面跟着一个闭包函数,函数有name、age入参,函数内部实现了PersonInfo初始化及其相关属性赋值,并返回了PersonInfo
3.最后在()代表调用该函数,"浩然",3代表的入参
在这里小伙伴可能疑惑了,为啥在没有进行忽略参数标签时(参数名前缀_),在调用时()内部添加标签?上一章闭包时讲解的,在闭包函数里不要外带参数名称,这里系统可能自动在入参前缀了_
如果大家觉得上面闭包有点臃肿,可以写一个函数,在属性赋值时调用,如:
class ViewModel{
lazy var person = self.creatPerson("浩然",3)
func creatPerson(_ name:String,_ age:Int) -> PersonInfo {
let info = PersonInfo()
info.name = name
info.age = 3
return info
}
}
注意:延迟加载属性时都是在类构造之后调用的,所以此时调用函数时,要用self.才可以
}
(3)计算属性:计算属性不直接存储值,而是提供一个 getter 和一个可选的 setter,来间接获取和设置其他属性或变量的值,不要用于获取、设置自身属性值.如:
class ViewModel{
var x:Double = 0.0
var y:Double = 0.0
var width:Double = 100.0
var height:Double = 200.0
var center:CGPoint{
get{
return CGPoint(x: x+width/2.0, y: y+height/2.0)
}
set(newValue){
x = Double(newValue.x) - width/2.0
y = Double(newValue.y) - height/2.0
}
}
}
调用:let model = ViewModel()
print(model.center)
model.center = CGPoint(x: 25, y: 10)
print(model.x)
输出:(50.0, 100.0) -25.0
(4)属性观察器:监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器
使用场景:自定义的存储属性、继承的存储属性、继承的计算属性(因为计算属性有set,放置观察期会报错,所以不需要观察期)
使用方法:
class PersonInfo {
var name:String = "浩然"{
willSet{
print("将要被设置:\(newValue)")
}
didSet{
print("之前的数据:\(oldValue)")
}
}
}
解析:willSet:代表这个属性将要被设置,newValue代表将要被设置的值
didSet:代表这个属性已被设置新值,oldValue代表之前的旧值
2.方法
类的方法分为实例方法和类方法
(1)实例方法:属于某个特定类、结构体或者枚举类型实例的方法,如:
class PersonInfo {
var name:String = "浩然"
var age:Int = 3
func showPerosnInfo(){
print("名字:\(name),年龄:\(age)")
}
}
let person = PersonInfo()
person.showPerosnInfo()
输出:名字:浩然,年龄:3
(2)类方法:属于某个特定类、结构体或者枚举类型的方法,如:
class PersonInfo {
var name:String = "浩然"
var age:Int = 3
class func showPerosnInfo(){
print("名字:\(name),年龄:\(age)")
}
}
PersonInfo.showPerosnInfo()
输出:名字:浩然,年龄:3
注意:class可以替换为:staic