Swift 属性

31 篇文章 1 订阅

属性将值跟特定的类、结构或枚举关联。存储属性存储常量或变量作为实例的一部分,而计算属性计算(不是存储)一个值。计算属性可以用于类、结构体和枚举,存储属性只能用于类和结构体。

存储属性和计算属性通常与特定类型的实例关联。但是,属性也可以直接作用于类型本身,这种属性称为类型属性。

另外,还可以定义属性观察器来监控属性值的变化,以此来触发一个自定义的操作。属性观察器可以添加到自己定义的存储属性上,也可以添加到从父类继承的属性上。

首先了解两个基本概念 类 实例

//1:类的概念  对全体的共有特性的抽象和封装,是一种类型.
class People{
    var name: String = ""
}

/*
 知识点:
  1):swift定义类的关键字是class.
  2):类的结构有以下几个部分:
    关键字class开始.
    使用{}包含类的主体
    class 和{}之间是类名,如上面People.
    swift 语言的代码规范是类名使用大写开头.
    类名后面可选扩展部分可以是继续也可以是遵守协议.
*/

//2实例

var people1=People()
let prople2=People()

/*
   people1,people2就是实例对象.语法如下: 变量类型符号let/var 对象名=类名()
*/

下面来看一下属性:

//定义一个类,添加相应的属性
class People{
    let gender: String = "Male"   // 性别,存储属性,实例属性
    var dream: String?            // 梦想,存储属性,实例属性
    var reality: String = ""      // 现实,存储属性,实例属性
    var lover: People?            // 爱人,存储属性,实例属性
    var isHappy: Bool{            // 你幸福吗?计算属性,实例属性
        get{
            if dream == reality || lover != nil{  //梦想照进现实或者有爱人
                return true
            }else{                //梦想很丰富现实很骨干.
                return false
            }
        }
    }
    
    class var plant: String{   //生存的新球,地球,计算属性,类型属性.
        return "earth"
    }
}

/*
  上面涉及了存储属性,计算属性,类型属性,实例属性.
  从属性归属的角度.可分为类型属性和实例属性.
  从属性的使用角度,可分为存储属性,计算属性.
*/
//使用点语法我们可以反问属性:
let jack = People()
jack.reality = "iOS developer!"  //给属性赋值
//jack.gender = "Women"    对常量存储属性进行赋值,编译器会提示错误,因为初始化之后其值就不能够改变.
print(jack.reality)       //iOS developer

存储属性

      存储属性:就是定义在类中的一个变量或者常量,因此有可以分为变量存储属性(使用var定义)和常量存储属性(使用let定义).上面的存储属性都是使用var来定义的,因为不管是梦想,还是爱人,都是可以变化的.但是性别是不变的.

惰性存储属性

      不仅有存储属性还有惰性存储属性,惰性存储属性是指当第一次被调用的时候才会计算其初始值的属性。好比如:类的有些属性是必须要有的,但不是一开始就有,经常出现在某个属性在类刚初始化的时候是没有的,只有到了一段时间或者某个条件触发后才存在.其定义格式如下: lazy var 变量名

下面看一个有趣的例子: 在我们读书的时候老师经常说"你这熊孩子,平时不烧香,临时抱佛脚!"

//定义一个类,然后给People加上一个惰性存储属性
class Buddha{
    var name: String
    init(name: String){
        self.name = name
    }
}

class People{
    let gender: String = "Male"   // 性别,存储属性,实例属性
    var dream: String?            // 梦想,存储属性,实例属性
    var reality: String = ""      // 现实,存储属性,实例属性
    var lover: People?            // 爱人,存储属性,实例属性
    var isHappy: Bool{            // 你幸福吗?计算属性,实例属性
        get{
            if dream == reality || lover != nil{  //梦想照进现实或者有爱人 
                return true
            }else{                //梦想很丰富现实很骨干.
                return false
            }
        }
    }
    
    class var plant: String{   //生存的新球,地球,计算属性,类型属性.
        return "earth"
    }
    
    lazy var buddha = Buddha(name: "释迦摩尼") //惰性存储属性
    func pray(){ //向佛祈祷,寻求帮助
       print("佛祖法号:\(buddha.name)")
    }
}

let youngCoder = People()   //小码农
youngCoder.pray()           //作业完不成,只能向佛祖祈祷

/*
   lazy var buddha = Buddha(name: "释迦摩尼")  //惰性存储属性
   这里虽然定义了buddha属性,并且等号右侧出现了Buddha初始化代码,但是这个阶段只做了类型的站位,而不会
   开屏任何实际空间给buddha属性,只有等第一次使用时才会分配空间,比如例子中youngCoder.pray() 之后,
   buddha属性才会被分配空间.
*/

我们可以通过LLDB 的调试一下,看看惰性属性是不是我们上面所说的那么回事:(分别在调用pray()方法之前和调用之后加相应的断点,并且在控制台输入print youngCoder)在没有调用pray()方法之前,看到如下输出:


 


  buddha.storage=nil,很明显buddha的存储空间是空的.在我们调用了pray()方法之后,我们在一次打印对象youngCoder,可以看到如下输出:


 
  现在就非常明显了,此时的buddha属性有存储空间了,并且有相应的内容.

注意事项:

  1):如果在类实例构造时无法知道属性所依赖的外部信息,则使用惰性属性.
  2):当属性的值需要复杂或者大量计算时,为了不阻塞对象的初始化,则使用惰性属性.
  3):必须将惰性存储属性声明成为变量,因为属性的值在实例构造完成之前可能无法得到.而常量属性在构造过程完成之前必须要有初始值,因此无法声明成常量属性.

计算属性

 4大特点:
       1):虽然是属性,但是却没有实际的内存空间,在类的结构中不占据内存位置.
       2):提供了取值访问器get和赋值访问器set,负责获取该属性的值,或者通过该属性给其他的存储属性负责.
       3):为Swift类属性增加了开闭原则.
       4):但凡计算属性必须是变量类型(var),因为计算属性值不确定.

看一个使用计算属性的例子:

class People{
    
    let gender: String = "Male"   // 性别,存储属性,实例属性
    var dream: String?            // 梦想,存储属性,实例属性
    var reality: String = ""      // 现实,存储属性,实例属性
    var lover: People?            // 爱人,存储属性,实例属性
    var appearance: String = ""
    
    var isHappy: Bool{           // 你幸福吗?计算属性,实例属性
        get{
            //梦想照进现实,或者有爱人,或者帅到睡不着,那就很幸福了!
            if dream != "" && (dream == reality) || lover != nil || appearance == "帅到睡不着"  {
                return true
            }else{
                return false
            }
        }
        
        //赋值访问器
        set(newIsHappy){
            if newIsHappy == true{
                appearance = "容光焕发"
            }else{
                appearance = "苦瓜脸"
            }
        }
    }
}

var oldCoder = People()
//其实,刚开始,老码并不幸福
print("old Coder is happy:\(oldCoder.isHappy)")//false
//如果小伙伴说老码幸福,那么就容光焕发了.
oldCoder.isHappy = true
print("老码的长相:\(oldCoder.appearance)") //老码的长相:容光焕发


上面使用了计算属性:非常简单下面一起来看一下语法:

取值访问器(get)标准格式如下:

var 计算属性: 类型{
    get{
        return 符合类型的值
    }
}

取值访问器(get)精简格式如下:

var 计算属性: 类型{

return 符合类型的值
}

赋值访问器(set)标准格式如下:
var 计算属性: 类型{
set(newValue){

}
}
赋值访问器(set)精简格式如下:
var 计算属性: 类型{

set{}//在精简格式下:set后面省略的参数默认为newValue,所以在set后面的{}实体里可以使用newValue来设置新值.

}

可以使用下面替代之前的(set)代码:

set{

if newValue{
   appearance = "容光焕发"
}else{
   appearance = "苦瓜脸"
}

}

只读控制

只读控制及开闭规则的实现,对于某些属性我们允许访问而不允许赋值,则称这类属性为只读属性.对外开放访问,对内赋值关闭,这是编程很重要的开闭原则.

比如老码是否开心的属性只能够看,而不能够由外人改变,自己的苦只有自己知道,这种情况下:isHappy就是一个只读属性.

var isHappy: Bool{        // 你幸福吗?计算属性,实例属性
        get{
            //梦想照进现实,或者有爱人,或者摔到睡不着,那就很幸福了!
            if dream != "" && (dream == reality) || lover != nil || appearance == "帅到睡不着"  {        
                return true
            }else{
                return false
         }
      }
}
类型属性

Swift编程语言中,类型属性是作为类型定义的一部分写在类型最外层的花括号内,因此它的作用范围也就在类型支持的范围内。使用关键字static来定义类型属性。在为类(class)定义计算型类型属性时,可以使用关键字class来支持子类对父类的实现进行重写。下面的例子演示了存储型和计算型类型属性的语法:

    static var storedTypeProperty = "Some value"
    static var computedTypeProperty: Int {
      return 1
    }
    class var stringComputedProperty: String {
        return "string"
    }
}

struct SomeStructure {
    static var storedTypeProperty = "Some value"
    static var computedTypeProperty: Int {
        return 1
    }
}

enum SomeEnumeration {
    static var storedTypeProperty = "Some value"
    static var computedTypeProperty: Int {
        return 6
    }
}
  注意:
 1定义类型属性的格式为class/staticvar 属性名:类型{get/set{}}
 2例子中的计算型类型属性是只读的,但也可以定义可读可写的计算型类型属性,跟实例计算属性的语法类似。
 3类型属性必须定义为变量类型而不是常量类型,因为类型属性是计算属性,计算属性必须是变量类型.
 4必须给类型属性指定默认值,因为类型属性不属于实例的范畴,不能够使用任何一个实例的构造器.

获取和设置类型属性的值

跟实例的属性一样,类型属性的访问也是通过点运算符来进行。但是,类型属性是通过类型本身来获取和设置,而不是通过实例。比如:

print("\(SomeStructure.storedTypeProperty),\(SomeStructure.computedTypeProperty)")//Some value,1
print(SomeEnumeration.storedTypeProperty) //Some value
print(SomeClass.stringComputedProperty) //string

属性观察器

属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,甚至新的值和现在的值相同的时候也不例外。

class People{

    var name: String = ""
    var lover: People? {        // 爱人,存储属性,实例属性
        willSet(newLover){      // lover属性值改变前被触发
            if (self.lover != nil){
                if (newLover != nil){
                  print("\(self.name) 移情别恋了 \(newLover!.name)")
                }
            }else{
                if (newLover != nil){  
                 print("\(self.name) 找到了糟糠之妻 \(newLover!.name)")
                }
            }
        }
        
        didSet(oldLover){
            if (oldLover != nil){
                print("\(self.name) 狠心的离开了 \(oldLover!.name)")
            }
        }
    }
}

var man = People()
man.name = "陈世美"

let lover1 = People()
lover1.name = "秦香莲"

let lover2 = People()
lover2.name = "大宋公主"

man.lover = lover1
man.lover = lover2

/*
属性观察器:
1)属性观察器分为两种:willSet(属性值改变前触发)和didSet(属性值改变后触发),其格式如下:
willSet(willSetValue){
    //willSetValue 可以用户自己定义
}
简化格式为:
willSet{
   //必须使用newValue作为参数
}

上面willSetValue/newValue代表将要使用的新值.
didSet(oldSetValue){
   //oldSetValue 可以用户自己定义

}
简化格式为:
didSet{

  //必须使用oldValue作为参数
}

2):属性观察器不能够用在惰性属性上,因为惰性存储属性是根据需要产生的,所以无法确定观察有效期.
3):对于可以重写的属性,可以在其子类中增加观察器,但是对于非重写属性则没有必要,因为可以在其赋值服务器中
触发观察的行为.
*/

全局变量和局部变量

计算属性和属性观察器所描述的模式也可以用于全局变量局部变量。全局变量是在函数、方法、闭包或任何类型之外定义的变量。局部变量是在函数、方法或闭包内部定义的变量。全局或局部变量都属于存储型变量,跟存储属性类似,它提供特定类型的存储空间,并允许读取和写入。

另外,在全局或局部范围都可以定义计算型变量和为存储型变量定义观察器。计算型变量跟计算属性一样,返回一个计算的值而不是存储值,声明格式也完全一样。

注意:全局的常量或变量都是延迟计算的,跟延迟存储属性相似,不同的地方在于,全局的常量或变量不需要标记lazy特性。局部范围的常量或变量不会延迟计算。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值