简要说明
名称 |
功能 |
set |
计算属性的赋值方法,设置属性的时候调用 |
get |
计算属性的读取方法,取属性值得时候调用 |
willSet(newValue) |
监视属性的方法,在属性值将要改变的时候调用,参数附带即将改变的值 |
didSet(oldValue) |
监视属性的方法,在属性值改变后调用,参数附带改变之前的值 |
? 和 ! |
属性的可空标识符. ?表示可空,!表示强制拆包 |
set和get
在OC中属性是由set和get方法来实现的,也就是说在打点调用属性的时候实际上是对属性的set和get方法进行调用,通过setget方法来实现对类中一个全局变量的读写,即时没有写set和get方法这两个方法也是隐式存在的.下面是OC中属性的实现原型
@property(nonatomic,copy)NSString * str;
xx.h
{
NSString * str;
}
- (void)setObject:(NSString *)anStr;
- (NSString *)getStr;
xx.M
{
NSString * _object;
}
- (void)setObject:(NSString *)anObject{
_object = anObject;
}
- (NSString *)getObject{
return _object;
}
看的出来,OC中得属性实际上是对类内部的一个全局变量的操作.我们可以通过重写set和get方法来实现属性变化的监听,属性的隐式修改等等.
而在swift中set和get方法并不是必须得.申明属性是直接生成一个存储属性,并不存在隐式的set和get方法,能够使用set和get方法的只有计算属性.计算属性本身并非一个值,只是一个能够通过打点调用set和get方法的假属性,计算属性并不能储存任何数据且必须实现get方法
class Object: NSObject {
var age:Int{
get{
print("get");
}
set(newValue){
print("(newValue)")
}
}
}
let man = People();
man.age = 10;
print("(man.age)")
输出结果:
set:10
get
0
可以看出 首先调用set方法 传递设置的值,newValue就是传递进来的值,设置完成后接着输出man.age属性,触发了get方法的调用,最后输出age的值,输出结果为0,也就是说并没有将设置的值保存起来.再来观察一下OC的属性原理,是不是和这个有点类似,如果在swift中创建一个私有的全局变量来储存set的值,读取的时候再返回这样就不就和OC中一样了吗?
private var newAge = 0;
var age:Int{
get{
print("get")
return newAge
}
set(newValue){
newAge = newValue;
print("set:(newValue)")
}
}
输出结果:
set:10
get
10
好了 这样就还原了OC中的属性格式,在这两个方法中我们可以对属性的值进行处理,由于swift中默认属性没有set和get方法 所以我们无法重写父类属性的set和get方法 .
willSet和didSet
这两个方法属于属性观察者.分别在属性值将要被设置和被设置以后调用.属于基本属性的方法,可以重写父类属性的这两个方法实现原有OC中重写set方法的功能.区别是初始化属性值的时候不会调用这两个方法.原理更加类似于通知,所以被成为属性观察者.
var name:String = "0"{
willSet(new){
print("will:(new)");
}
didSet(old){
print("did:(old)");
}
}
var man = People()
man.name = "sad";
print("(man.name)");
输出结果::
will:sad
did:0
sad
测试结果显示,在第一次属性初始化为0的时候,观察者方法并没有调用,只有外部使用改变name值的时候才调用了观察者方法.
?和!
可空属性
在swift中所有的属性变量默认都不能为空,如果不可避免的可能造成为空属性.则需要声明为可空属性.
var name:string = "王五花"
var name:string?
swift中空属性和OC中的空属性不同,虽然可以直接使用name == nil 或name != nil 来判断,但是不可直接使用里面的值进行赋值操作.这里就要说一下这个箱子概念了,当一个属性为可空的时候,这个属性被放到一个箱子中,这个箱子只有空和非空两种状态,由于属性是在箱子中的所以我们无法直接使用这个属性值,需要对箱子进行拆解操作man.name = name! 如果不拆箱,这个属性的类型是箱子的类型.
let man:People = People()
if man.name == nil {
print("空")
}
man.name = "wang";
print("没有进行拆包的值:(man.name)")
if man.name != nil {
print("拆包以后的值:(man.name!)")
}
let str:String = man.name!;
let op:Optional = man.name;
print("(op)")
print("str会在接受值的时候强制拆箱操作:(str)")
输出结果:
空
没有进行拆包的值:Optional("wang")
拆包以后的值:wang
Optional("wang")
str会在接受值的时候强制拆箱操作:wang
也就是说,当我们声明一个可空属性的时候var name:string? ,这个属性被一个叫做Optional 的箱子装了起来,这个箱子是允许为空的,使用man.name == nil 语句来判断这个箱子里面有没有值,如果没有返回空,如果有则不为空.使用man.name = "wang"; 来向箱子中存放一个值,这个值必须和声明时的类型相同,当我们需要使用箱子的值的时候如果直接使用那么得到的是Optional值,并非是箱子中的值,所以要想使用箱子中的值需要使用! 将箱子打开man.name! 使用之前最好判断下
还有一种状态,就是在可空属性下面还有属性的时候
class People: NSObject {
var name:Name?
}
class Name: NSObject {
var English:String?
var Chinese:String = ""
}
这时使用name属性就要格外当心了.虽然系统会提示.
override func viewDidLoad() {
super.viewDidLoad()
let man:People = People()
man.name?.Chinese = "王"
print("(man.name?.Chinese)");
man.name = Name()
man.name?.Chinese = "王五花"
print("(man.name?.English)")
print("(man.name!.Chinese)")
man.name?.English = "WangWuhua"
print("(man.name?.English)")
print("(man.name?.English!)")
print("(man.name!.English)")
print("(man.name!.English!)")
}
总结
- set和get方法在Swift中没有默认创建,在基本属性中并不存在,所以无法重写父类的非计算属性的set和get方法.主要作用于对属性值在写入和读取过程中进行计算操作
- willSet和didSet类似于OC中得KVO,用于监视属性值的变化
- 可空属性,使用
var 属性名:类名? 这种方式可以声明一个可空属性,这里 ? 表示可空.这样系统将属性放到一个箱子中,通过对箱子是否为空的判断来确定是否有值,如果想要使用箱子中得值必须使用 ! 来强制打开箱子.如果属性下面还有属性需要使用 对象.属性?.属性A 来对属性进行一次是否为空得判断,如果为空则不调用属性A,如果确定有值可以使用 对象.属性!.属性A 来得到属性A的值 如果属性A也是可空类型 则需要 对象.属性!.属性A! 将每层的箱子都打开才能得到属性A的值
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|