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

存储属性和计算属性通经常使用于特定类型的实例,可是,属性也能够直接用于类型本身,这样的属性称为类型属性。

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

存储属性

简单来说,一个存储属性就是存储在特定类或结构体的实例里的一个常量或变量,存储属性能够是变量存储属性(用keywordvar定义),也能够是常量存储属性(用keywordlet定义)。

能够在定义存储属性的时候指定默认值,请參考构造过程一章的默认属性值一节。也能够在构造过程中设置或改动存储属性的值,甚至改动常量存储属性的值,请參考构造过程一章的在初始化阶段改动常量存储属性一节。

以下的样例定义了一个名为FixedLengthRange的结构体,他描写叙述了一个在创建后无法改动值域宽度的区间:

struct FixedLengthRange {
var firstValue: Int
let length: Int
}
var rangeOfThreeItems =FixedLengthRange(firstValue: 0, length: 3)
// 该区间表示整数0,1,2
rangeOfThreeItems.firstValue = 6
// 该区间如今表示整数6,7,8

FixedLengthRange的实例包括一个名为firstValue的变量存储属性和一个名为length的常量存储属性。在上面的样例中,length在创建实例的时候被赋值,由于它是一个常量存储属性,所以之后无法改动它的值。

常量和存储属性

假设创建了一个结构体的实例并赋值给一个常量,则无法改动实例的不论什么属性,即使定义了变量存储属性:

let rangeOfFourItems =FixedLengthRange(firstValue: 0, length: 4)
// 该区间表示整数0,1,2,3
rangeOfFourItems.firstValue = 6
// 虽然firstValue诗歌变量属性,这里还是会报错

由于rangeOfFourItems声明成了常量(用letkeyword),即使firstValue是一个变量属性,也无法再改动它了。

这样的行为是因为结构体(struct)属于值类型。当值类型的实例被声明为常量的时候,它的全部属性也就成了常量。

属于引用类型的类(class)则不一样,把一个引用类型的实例赋给一个常量后,仍然能够改动实例的变量属性。

延迟存储属性

延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用@lazy来标示一个延迟存储属性。

注意:

必须将延迟存储属性声明成变量(使用varkeyword),由于属性的值在实例构造完毕之前可能无法得到。而常量属性在构造过程完毕之前必需要有初始值,因此无法声明成延迟属性。

延迟属性非常实用,当属性的值依赖于在实例的构造过程结束前无法知道详细值的外部因素时,或者当属性的值须要复杂或大量计算时,能够仅仅在须要的时候来计算它。

以下的样例使用了延迟存储属性来避免复杂类的不必要的初始化。样例中定义了DataImporter和DataManager两个类,以下是部分代码:

class DataImporter {
/*
DataImporter 是一个将外部文件里的数据导入的类。
这个类的初始化会消耗不少时间。
*/
var fileName = "data.txt"
// 这是提供数据导入功能
} class DataManager {
@lazy var importer = DataImporter()
var data = String[]()
// 这是提供数据管理功能
} let manager = DataManager()
manager.data += "Some data"
manager.data += "Some more data"
// DataImporter 实例的 importer 属性还没有被创建

DataManager类包括一个名为data的存储属性,初始值是一个空的字符串(String)数组。尽管没有写出所有代码,DataManager类的目的是管理和提供对这个字符串数组的訪问。

DataManager的一个功能是从文件导入数据,该功能由DataImporter类提供,DataImporter须要消耗不少时间完毕初始化:由于它的实例在初始化时可能要打开文件,还要读取文件内容到内存。

DataManager也可能不从文件里导入数据。所以当DataManager的实例被创建时,不是必需创建一个DataImporter的实例,更明智的是当用到DataImporter的时候才去创建它。

因为使用了@lazy,importer属性仅仅有在第一次被訪问的时候才被创建。比方訪问它的属性fileName时:

println(manager.importer.fileName)
// DataImporter 实例的 importer 属性如今被创建了
// 输出 "data.txt”

存储属性和实例变量

假设您有过 Objective-C 经验,应该知道有两种方式在类实例存储值和引用。对于属性来说,也能够使用实例变量作为属性值的后端存储。

Swift 编程语言中把这些理论统一用属性来实现。Swift中的属性没有相应的实例变量,属性的后端存储也无法直接訪问。这就避免了不同场景下訪问方式的困扰,同一时候也将属性的定义简化成一个语句。一个类型中属性的所有信息——包含命名、类型和内存管理特征——都在唯一一个地方(类型定义中)定义。

计算属性

除存储属性外,类、结构体和枚举能够定义计算属性,计算属性不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其它属性或变量的值。

struct Point {
var x = 0.0, y = 0.0
}
struct Size {
var width = 0.0, height = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set(newCenter) {
origin.x = newCenter.x - (size.width / 2)
origin.y = newCenter.y - (size.height / 2)
}
}
}
var square = Rect(origin: Point(x: 0.0, y:0.0),
size: Size(width: 10.0, height: 10.0))
let initialSquareCenter = square.center
square.center = Point(x: 15.0, y: 15.0)
println("square.origin is now at(\(square.origin.x), \(square.origin.y))")
// 输出"square.origin is now at (10.0, 10.0)”

这个样例定义了 3 个几何形状的结构体:

Point封装了一个(x, y)的坐标

Size封装了一个width和height

Rect表示一个有原点和尺寸的矩形

Rect也提供了一个名为center的计算属性。一个矩形的中心点能够从原点和尺寸来算出,所以不须要将它以显式声明的Point来保存。Rect的计算属性center提供了自己定义的 getter 和 setter 来获取和设置矩形的中心点,就像它有一个存储属性一样。

样例中接下来创建了一个名为square的Rect实例,初始值原点是(0, 0),宽度高度都是10。如图所看到的蓝色正方形。

square的center属性能够通过点运算符(square.center)来訪问,这会调用getter 来获取属性的值。跟直接返回已经存在的值不同,getter 实际上通过计算然后返回一个新的Point来表示square的中心点。如代码所看到的,它正确返回了中心点(5, 5)。

center属性之后被设置了一个新的值(15, 15),表示向右上方移动正方形到如图所看到的橙色正方形的位置。设置属性center的值会调用 setter 来改动属性origin的x和y的值,从而实现移动正方形到新的位置。

便捷 setter 声明

假设计算属性的 setter 未定义表示新值的參数名,则能够使用默认名称newValue。以下是使用了便捷 setter 声明的Rect结构体代码:

struct AlternativeRect {
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set {
origin.x = newValue.x - (size.width / 2)
origin.y = newValue.y - (size.height / 2)
}
}
}

仅仅读计算属性

仅仅有 getter 没有 setter 的计算属性就是仅仅读计算属性。仅仅读计算属性总是返回一个值,能够通过点运算符訪问,但不能设置新的值。

注意:

必须使用varkeyword定义计算属性,包含仅仅读计算属性,由于他们的值不是固定的。letkeyword仅仅用来声明常量属性,表示初始化后再也无法改动的值。

仅仅读计算属性的声明能够去掉getkeyword和花括号:

struct Cuboid {
var width = 0.0, height = 0.0, depth = 0.0
var volume: Double {
return width * height * depth
}
}
let fourByFiveByTwo = Cuboid(width: 4.0,height: 5.0, depth: 2.0)
println("the volume of fourByFiveByTwois \(fourByFiveByTwo.volume)")
// 输出 "the volumeof fourByFiveByTwo is 40.0"

这个样例定义了一个名为Cuboid的结构体,表示三维空间的立方体,包括width、height和depth属性,另一个名为volume的仅仅读计算属性用来返回立方体的体积。设置volume的值毫无意义,由于通过width、height和depth就能算出volume。然而,Cuboid提供一个仅仅读计算属性来让外部用户直接获取体积是非常实用的。

Swift编程语言学习9—— 存储属性和计算属性的更多相关文章

  1. Swift面向对象基础(中)——Swift中的存储属性和计算属性

    学习来自<极客学院> 1.存储属性:存储在类.结构体里的变量或者常量 2.分为:实例存储属性.类型存储属性 3.所有的存储属性必须显示的指定初始值,在定义时或者构造器当中指定 4.可选类型 ...

  2. Swift编程语言学习10—— 枚举属性监视器

    属性监视器 属性监视器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性监视器.甚至新的值和如今的值同样的时候也不例外. 能够为除了延迟存储属性之外的其它存储属性加入属性监视器,也能够通过重载 ...

  3. Swift类与结构、存储属性、计算属性、函数与方法、附属脚本等

    写了12个Person来复习,不过完成同样的代码需要敲键盘的次数相比OC确实少了很多,这很多应该归功于Swift中不写分号,以及少了OC中的中括号. 一.类与结构体 两者在Swift中差不了多少了 类 ...

  4. Swift编程语言学习11—— 枚举全局变量、局部变量与类型属性

    全局变量和局部变量 计算属性和属性监视器所描写叙述的模式也能够用于全局变量和局部变量,全局变量是在函数.方法.闭包或不论什么类型之外定义的变量,局部变量是在函数.方法或闭包内部定义的变量. 前面章节提 ...

  5. swift学习笔记之--类的计算属性

    1,Swift中类可以使用计算属性,即使用get和set来间接获取/改变其他属性的值,代码如下 class Calcuator{ ; ; var sum:Int{ get{ return a + b ...

  6. swift 存储属性和计算属性 set{}和get{} didSet{}和willSet{}

    首先我们看一段代码: var A:Int = 0 var B:Int = 0 var C:Int { get { return 1 } set { print("Recived new va ...

  7. 《从零开始学Swift》学习笔记(Day 33)——属性观察者

    原创文章,欢迎转载.转载请注明:关东升的博客 为了监听属性的变化,Swift提供了属性观察者.属性观察者能够监听存储属性的变化,即便变化前后的值相同,它们也能监听到. 属性观察者主要有以下两个: l ...

  8. Swift编程语言学习12 ——实例方法(Instance Methods)和类型方法(Type Methods)

    方法是与某些特定类型相关联的函数.类.结构体.枚举都能够定义实例方法:实例方法为给定类型的实例封装了详细的任务与功能.类.结构体.枚举也能够定义类型方法:类型方法与类型本身相关联.类型方法与 Obje ...

  9. Vue.js 学习笔记 第3章 计算属性

    本篇目录: 3.1 什么是计算属性 3.2 计算属性用法 3.3 计算属性缓存 模板内容的表达式常用语简单的运算,当其过长或逻辑复杂时,会难以维护,本章的计算属性就是用于解决该问题的. 3.1 什么是 ...

随机推荐

  1. Cocos2D-X扫盲之坐标系、锚点

    一.引言 在Cocos2D-X的开发过程中,经常会碰到设置精灵位置的问题.而设置位置的过程,涉及到两个问题:第一是坐标系,包括原点的位置.X/Y坐标轴的方向灯:第二是基准点(Cocos2D-X中叫锚点 ...

  2. IOS 调用系统相册或照相机tab按钮显示中文

  3. WCF技术剖析之二十五: 元数据(Metadata)架构体系全景展现[元数据描述篇]

    原文:WCF技术剖析之二十五: 元数据(Metadata)架构体系全景展现[元数据描述篇] 在[WS标准篇]中我花了很大的篇幅介绍了WS-MEX以及与它相关的WS规范:WS-Policy.WS-Tra ...

  4. Android项目实战手机安全卫士(01)

    目录 项目结构图 源代码 运行结果 项目结构图 源代码 SplashActivity.java package com.coderdream.mobilesafe.activity; import a ...

  5. 相邻数字的基数等比确定进制问题pojg2972

    解决数制转换问题时,如果所给的数值不是用十进制表示的,一般用一个字符型数组来存放,数组的每个元素分别存储它的一位数字.然后按位转换求和,得到十进制表示,再把十进制转成成其他所求的进制表示.转成的结果也 ...

  6. Android 去掉Activity的跳转动画

    startActivity或finish的时候调用一句话即可: overridePendingTransition(0, 0);

  7. K&amp;R练习题6-1统计关键词出现的次数

    这道练习题训练了: 1.结构体数组 2.二分查找 3.指针操作 ---- 都不难.但非常基础,我认为非常好,做完了记到博客上来,题目见k&R,实现例如以下: /* * Practice of ...

  8. 浅谈PPM (Project Portfolio Management) - 1

    前言: 本文以纯理论性的PPM解说为主,不会涉及到具体怎样实施,我会在以后介绍具体的PPM实施方案介绍. PPM,可能非常多人并不清楚甚至可能没听说过,这是一个近些年才流行起来的概念,是Project ...

  9. Qt读取ANSI格式文件——利用QTextCodec将其他编码格式的QByteArray转换为Unicode格式,或者从文件中读出后直接做转换

    t使用Unicode来表示字符串.但是通常需要访问一些非Unicode格式的字符串,例如打开一个GBK编码的中文文本文件,甚至一些非Unicode编码的日文,俄文等. Qt提供了QTextCodec类 ...

  10. WCF技术剖析之一:通过一个ASP.NET程序模拟WCF基础架构

    原文:WCF技术剖析之一:通过一个ASP.NET程序模拟WCF基础架构 细算起来,已经有好几个月没有真正的写过文章了.近半年以来,一直忙于我的第一本WCF专著<WCF技术剖析>的写作,一直 ...