Swift3.0属性(Properties)

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

存储属性和计算属性通常和特定的实例类型进行关联。但是,属性也可以作用与类型背身,这样的属性成为类型属性。

另外也可以通过定义属性观察期来监控属性值的改变,从而进行一个自定义的操作。属性观察器可以添加到自己定义的存储属性上,也可以添加到负累继承的属性上。

存储属性(Stored Properties)

简单来说,存储属性就是用来存储特定类或结构体实例中的一个常量(变量)。

可以在定义存储属性的时候给定默认值,也可以在构造的过程中设置或者修改存储属性的值,甚至是修改常量存储属性的值。

Stored Properties🌰

常量结构体实例的存储属性(Stored Properties of Constant Structure Instances)

如果创建了一个结构体的实例并赋值给了一个常量,即使有属性被声名为变量也无法修改该实例的任何属性:


报错了

这是因为结构体是值类型,当值类型的实例被声名为常量时,它的所有属性也都成了常量。
所以如果一个引用类型的实例赋给一个常量后,还是可以修改它的变量属性,就像类(class)。

延迟存储属性(Lazy Stored Properties)

延迟存储属性指当第一次被调用的时候才会计算初始值的属性,在属性声名前使用 lazy 关键字来标明一个延迟储存属性。

必须将延迟存储属性声名为变量(var),因为属性的初始值可能在实例构造完之后才会创建。但是常量属性在构造过程中必须要有初始值,所以没有办法声名成延迟属性。

延迟属性很有用,当属性的值依赖于在实例的构造过程结束后才会知道影响值的外部因素时,或者当获得属性的初始值需要复杂或大量计算时,可以只在需要的时候计算它:


Lazy Stored Properties🌰

注意
如果一个被 lazy 标记的属性,在没有初始化的时候被多个线程访问,这种情况下不会保证只被创建一次。

存储属性和实例变量(Stored Properties and Instance Variables)

OC中为类实例存储值和引用提供了两种方法,除了实例之外还可以使用实例变量作为属性值的后端存储。

Swift中将这些概念都统一到属性中。Swift的属性没有对应的实例变量,属性的后端存储也不能直接访问。这样就能避免了不同场景下访问方式的困扰,同时也可以把属性的定义简化为一个语句。属性的全部信息——包括命名、类型和内存管理特性——都在唯一一个地方(类型定义中)定义。

计算属性(Computed Properties)

除了存储属性之外,类、结构体和枚举可以定义计算属性,这种属性实际上不能存储之。但是,会提供 getter 和可选的 setter 方法用来间接存储其他的属性和值:


Computed Properties 🌰

便捷 Setter 声名(Shorthand Setter Declaration)

如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称 newValue:


Shorthand Setter Declaration 🌰

只读计算属性(Read-Only Computed Properties)

只有 getter 没有 setter 的计算属性就是只读计算属性。只读计算属性总是返回一个值,可以通过点语法访问,但是不能设置新的值。

注意
只能用 var 来声名计算属性,因为计算属性不是固定的。用 let 只能来定义常量属性,表示初始化后再也无法修改的值。

只读计算属性可以去掉 get 关键字和括号:


Read-Only Computed Properties 🌰

属性观察器(Property Observers)

属性观察器监控和响应值的变化。每次属性的值被设置的时候都会调用属性观察器,甚至是新的值和当前值相同的时候。

可以给除了延时存储属性之外的任何存储属性添加属性观察器。也可以通过重写属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器。不必为非重写的计算属性添加属性观察器,因为可以通过它的 setter 直接监控和响应值的变化。

可以给属性添加一个或全部的观察器:

  • willSet 在值被存储之前被调用。
  • didSet 在新的值被存储之后立即调用。

willSet 观察器会将新的值作为常量传入,在 willSet 的实现代码中可以为这个参数指定一个名称,如果不指定,则新的值用 newValue 表示。

相似的,实现 didSet 观察器用一个常量参数表示旧的值,可以为该参数命名或者使用默认名称 oldValue 。如果在 didSet 中再次对该值赋值,那么新的值会覆盖旧的值。

注意
父类的属性在子类的构造器中被赋值时,它在父类中的 willSet 和 didSet 会被调用,然后才会调用子类的观察器。在父类初始化方法调用之前,子类给属性赋值时,观察器是不会被调用的。

Property Observers 🌰

注意
如果将属性用 in-out 的方式传入函数,willSet 和 didSet 也会调用。这是因为 in-out 参数是拷入拷出模式:就是在函数内部使用的是参数的 copy,函数结束后,又对参数重新赋值。

全局和局部变量(Global and Local Variables)

计算属性和属性观察器所描述的属性也可以用在全局变量和局部变量中。全局变量是被定义在方法、函数、闭包或任何类型之外定义的变量。局部变量在函数、方法或闭包内部定义的变量。

前面提到的全局或局部变量都是属于存储变量,和存储属性类似,它为特定类型的值提供存储空间并允许值的读写。

除此之外,也可以在全局或局部范围定义计算变量和为存储变量定义观察器。计算变量和计算属性一样,返回一个计算结果而不是返回存储值,声名格式也完全一样。

注意
全局的常量(变量)都是延迟计算的,跟延迟存储属性类似,不同的地方在于,全局的常量(变量)不需要 lazy 修饰符。
局部的常量(变量)从不延迟计算。

类型属性(Type Properties)

实例属性就是一个特定类型的实例,每次创建一个新的实例,它都会有一套属于自己的属性值,并且每个实例之间的属性都是相互独立的。

也可以为类型本身定义属性,所以无论创建了多少个实例,这样的属性都只有唯一的一份。这样的属性就是类型属性。

类型属性就是用来共享某个类型的所有实例的数据,比如所有实例都能用一个常量(像C语言中的静态常量),或者都能用一个变量(C语言中的静态变量)

存储型类型属性可以是常量或者变量,但是计算型类型属性只能为变量。

注意
和存储实例属性不同,必须给存储型属性一个默认值。这是因为在存储型类型属性在初始化的时候并没有构造器为其赋值。
存储型类型属性是延迟初始化的,它们只有在第一次被访问的时候才会初始化。即使它们被多个线程同事访问,系统也保证只会对其初始化一次,并且不需要 lazy 修饰符。

类型属性语法(Type Property Syntax)

在C语言和OC中,与某个类型关联的静态常量(变量),是作为全局静态变量定义的。但是在Swift中,类型属性是作为类型的一部分写在类型最外层的括号内的,所以它的作用范围就是类型支持的范围内。

用 static 关键字来定义类型属性。在为类定义计算型类型属性时,可以改用 class 关键字来支持子类对父类的实现进行重写:


Type Property Syntax 🌰

🌰中的计算型类型属性是只读的,但也可以定义可读写的计算型类型属性,跟计算型实例属性的语法相同。

查询和设置类型属性(Querying and Setting Type Properties)

和实例属性一样,类型属性也是通过点语法来访问的。但是类型属性是通过类型本身进行访问的,而不是通过实例:


Querying and Setting Type Properties 🌰

下面有一个🌰,定义一个结构体来表示音量,每个声道的音量都是0-10之间的整数:


左声道音量为9,右声道音量为7
🌰1

注意
在第一个检查过程中,didSet 属性观察期将 currentLevel 设置成了不同的值,但是这不会造成属性观察期被再次调用。

🌰2
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,511评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,495评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,595评论 0 225
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,558评论 0 190
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,715评论 3 270
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,672评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,112评论 2 291
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,837评论 0 181
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,417评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,928评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,316评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,773评论 2 234
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,253评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,827评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,440评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,523评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,583评论 2 249

推荐阅读更多精彩内容

  • Swift语法基础(五)-- (类和结构体、属性、方法) 本章将会介绍 类和结构体对比结构体和枚举是值类型类是引用...
    寒桥阅读 1,048评论 0 1
  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young阅读 3,656评论 1 10
  • 常量与变量使用let来声明常量,使用var来声明变量。声明的同时赋值的话,编译器会自动推断类型。值永远不会被隐式转...
    莫_名阅读 388评论 0 1
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,048评论 18 139
  • 洁白的球鞋蓝蓝的天 清清的河水肩上的蝶 金黄的油菜软软的棉 漫漫的时光天真的脸 歌唱的鸟儿翩翩的叶 弯弯的小路远方...
    清白脸庞阅读 400评论 4 13