Swift学习笔记(八)·类的属性、方法

172 阅读5分钟

引言:上一章中我们介绍了类的初始化,以及属性,本章中我们将详细介绍类的属性、方法等

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.后面跟着一个闭包函数,函数有nameage入参,函数内部实现了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