【Swift学习】Swift编程之旅---属性(十四)
属性关联特定类、结构或枚举的值,存储属性将存储常量和变量作为实例的一部分,计算属性用于计算一个值,而不进行存储。计算属性可以用于类、结构体和枚举里,存储属性只能用于类和结构体。存储属性和计算属性通常用于特定类型的实例,但是,属性也可以直接用于类型本身,这种属性称为类型属性。另外,还可以定义属性监视器来观察属性值的变化,以此来触发一个自定义的操作。属性监视器可以添加到存储属性上,也可以添加到从父类继承的属性。
Stored Properties存储属性
存储属性可以是常量或变量,你可以给存储属性设置默认值也可以在构造过程中设置或修改存储属性的值,甚至修改常量存储属性的值
struct FixedLengthRange {
var firstValue: Int
let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: , length: )
rangeOfThreeItems.firstValue =
FixedLengthRange的实例包含一个名为firstValue的变量存储属性和一个名为length的常量存储属性。在上面的例子中,length在创建实例的时候被赋值,因为它是一个常量存储属性,所以之后无法修改它的值。
let rangeOfFourItems = FixedLengthRange(firstValue: , length: )
// this range represents integer values 0, 1, 2, and 3
rangeOfFourItems.firstValue =
// this will report an error, even though firstValue is a variable property
因为rangeOfFourItems声明成了常量,即使firstValue是一个变量属性,也无法再修改它了。这是由于结构体(struct)属于值类型。当值类型的实例被声明为常量的时候,它的所有属性也就成了常量。属于引用类型的类(class)则不一样,把一个引用类型的实例赋给一个常量后,仍然可以修改实例的变量属性。
延迟存储属性
延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用lazy关键字来申明一个延迟存储属性。
注意:必须将延迟存储属性声明成变量(使用var关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
class DataImporter {
/*
DataImporter is a class to import data from an external file.
The class is assumed to take a non-trivial amount of time to initialize.
*/
var fileName = "data.txt"
// the DataImporter class would provide data importing functionality here
}
class DataManager {
lazy var importer = DataImporter()
var data = [String]()
// the DataManager class would provide data management functionality here
}
let manager = DataManager()
manager.data.append("Some data")
manager.data.append("Some more data")
// the DataImporter instance for the importer property has not yet been created
DataManager类包含一个名为data的存储属性,初始值是一个空的字符串(String)数组。DataManager类的目的是管理和提供对这个字符串数组的访问。
计算属性
计算属性不直接存储值,而是提供一个 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 / )
let centerY = origin.y + (size.height / )
return Point(x: centerX, y: centerY)
}
set(newCenter) {
origin.x = newCenter.x - (size.width / )
origin.y = newCenter.y - (size.height / )
}
}
}
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)的坐标
Rect也提供了一个名为center的计算属性。一个矩形的中心点可以从原点和尺寸来算出,所以不需要将它以显式声明的Point来保存。Rect的计算属性center提供了自定义的 getter 和 setter 来获取和设置矩形的中心点,就像它有一个存储属性一样。

简单setter声明
如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称newValue。下面是使用了便捷 setter 声明的Rect结构体代码:
struct AlternativeRect {
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width / )
let centerY = origin.y + (size.height / )
return Point(x: centerX, y: centerY)
}
set {
origin.x = newValue.x - (size.width / )
origin.y = newValue.y - (size.height / )
}
}
}
只读计算属性
只有 getter 没有 setter 的计算属性就是只读计算属性。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。只读计算属性的声明可以去掉get关键字和花括号
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 fourByFiveByTwo is \(fourByFiveByTwo.volume)")
// 输出 "the volume of fourByFiveByTwo is 40.0"
属性观察
观察属性值的变化,当发生变化时实现自定义操作。可以为属性添加如下的一个或全部监视器:
- willSet在属性值变化前调用
- didSet在属性值变化后立即调用
willSet监视器会将新的属性值作为固定参数传入,在willSet的实现代码中可以为这个参数指定一个名称,如果不指定则参数仍然可用,这时使用默认名称newValue表示。
似地,didSet监视器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名oldValue。
注意:willSet和didSet监视器在属性初始化过程中不会被调用,他们只会当属性的值在初始化之外的地方被设置时被调用。
class StepCounter {
var totalSteps: Int = {
willSet(newTotalSteps) {
print("About to set totalSteps to \(newTotalSteps)")
}
didSet {
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps =
// About to set totalSteps to 200
// Added 200 steps
stepCounter.totalSteps =
// About to set totalSteps to 360
// Added 160 steps
stepCounter.totalSteps =
// About to set totalSteps to 896
// Added 536 steps
StepCounter类定义了一个Int类型的属性totalSteps,它是一个存储属性,包含willSet和didSet监视器。
注意:如果在didSet监视器里为属性赋值,这个值会替换监视器之前设置的值。
类型属性
实例属性是属于特定类型的实例的属性。每次创建该类型的新实例时,它都有它自己的一组属性值,与任何其他实例分离,也可以为类型本身定义属性,不管类型有多少个实例,这些属性都只有唯一一份。这种属性就是类型属性。
类型属性语法
使用关键字static来定义值类型的类型属性,关键字class来为类(class)定义类型属性。下面的例子演示了存储型和计算型类型属性的语法
struct SomeStructure {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
// 这里返回一个 Int 值
}
}
enum SomeEnumeration {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
// 这里返回一个 Int 值
}
}
class SomeClass {
class var computedTypeProperty: Int {
// 这里返回一个 Int 值
}
}
获取和设置类型属性的值
实例的属性一样,类型属性的访问也是通过点运算符来进行,但是,类型属性是通过类型本身来获取和设置,而不是通过实例。比如
println(SomeClass.computedTypeProperty)
// 输出 "42" println(SomeStructure.storedTypeProperty)
// 输出 "Some value."
SomeStructure.storedTypeProperty = "Another value."
println(SomeStructure.storedTypeProperty)
// 输出 "Another value.”
下面的例子定义了一个结构体,使用两个存储型类型属性来表示多个声道的声音电平值,每个声道有一个 0 到 10 之间的整数表示声音电平值。

struct AudioChannel {
static let thresholdLevel =
static var maxInputLevelForAllChannels =
var currentLevel: Int = {
didSet {
if currentLevel > AudioChannel.thresholdLevel {
// 将新电平值设置为阀值
currentLevel = AudioChannel.thresholdLevel
}
if currentLevel > AudioChannel.maxInputLevelForAllChannels {
// 存储当前电平值作为新的最大输入电平
AudioChannel.maxInputLevelForAllChannels = currentLevel
}
}
}
}
结构AudioChannel定义了 2 个存储型类型属性来实现上述功能。第一个是thresholdLevel,表示声音电平的最大上限阈值,它是一个取值为 10 的常量,对所有实例都可见,如果声音电平高于 10,则取最大上限值 10(见后面描述)。
var leftChannel = AudioChannel()
var rightChannel = AudioChannel()
如果将左声道的电平设置成 7,类型属性maxInputLevelForAllChannels也会更新成 7:
leftChannel.currentLevel =
println(leftChannel.currentLevel)
// 输出 "7"
println(AudioChannel.maxInputLevelForAllChannels)
如果试图将右声道的电平设置成 11,则会将右声道的currentLevel修正到最大值 10,同时maxInputLevelForAllChannels的值也会更新到 10:
rightChannel.currentLevel =
println(rightChannel.currentLevel)
// 输出 "10"
println(AudioChannel.maxInputLevelForAllChannels)
【Swift学习】Swift编程之旅---属性(十四)的更多相关文章
- python#父与子的编程之旅#第十四章
1. 为BankAccount 建立一个类定义.它应该有一些属性,包括账户名(一个字符串).账号(一个字符串或整数)和余额(一个浮点数),另外还要有一些方法显示余额.存钱和取钱. class Bank ...
- JAVA之旅(十四)——静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制
JAVA之旅(十四)--静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制 JAVA之旅,一路有你,加油! 一.静态同步函数的锁是clas ...
- Swift学习——Swift基础具体解释(一)
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/zhenyu5211314/article/details/34807025 注:由于基础部分在Swi ...
- 《Linux命令行与shell脚本编程大全》 第十四章 学习笔记
第十四章:呈现数据 理解输入与输出 标准文件描述符 文件描述符 缩写 描述 0 STDIN 标准输入 1 STDOUT 标准输出 2 STDERR 标准错误 1.STDIN 代表标准输入.对于终端界面 ...
- 视觉slam学习之路(一)看高翔十四讲所遇到的问题
目前实验室做机器人,主要分三个方向,定位导航,建图,图像识别,之前做的也是做了下Qt上位机,后面又弄红外识别,因为这学期上课也没怎么花时间在项目,然后导师让我们确定一个方向来,便于以后发论文什么. ...
- Swift学习——Swift解释特定的基础(七)
Implicitly Unwrapped Optionals 隐式解析选项 如上所述.可选意味着常数或变量"没有值".通过可选if声明来推断是否存在值,假设有值析值. 有时候 ...
- Swift学习——Swift解释具体的基础(六)
Optionals 可选 可选(它似乎并不如此翻译)它适用于那些值这种情况可能是空的,有两种情况一个可选:存在值并等于x,要么值不存在. 选配的概念在OC和C里面并没有.在OC中最接近的概念就是 ...
- Python学习之旅(十四)
Python基础知识(13):函数(Ⅳ) Python内置函数 1.abs:取绝对值 abs(-1) 1 2.all:把序列中的每一个元素拿出来做布尔运算,都为真则返回True,如果序列中有None. ...
- Swift学习--闭包中的懒加载(四)
class ViewController: UIViewController { //格式:定义变量时前使用lazy来修饰变量,后面通过等到赋值一个闭包 // 注意点:1.必须是用var 2.闭包后面 ...
随机推荐
- PL/SQL Developer登入时候报ORA-12638: 身份证明检索失败的解决办法
找到安装目录:C:/oracle/product/10.2.0/db_1/NETWORK/ADMIN 打开sqlnet.ora 在里面找到 SQLNET.AUTHENTICATION_SERVICES ...
- RCP: JDT 根据org.eclipse.jdt.core.IJavaElement对象获取org.eclipse.jdt.core.dom.ASTNode对象
JDT中有两套Java文件模型映射. 其核心类\接口分别为: org.eclipse.jdt.core.IJavaElement和org.eclipse.jdt.core.dom.ASTNode IJ ...
- 【译】什么导致了Context泄露:Handler&内部类
思考下面代码 public class SampleActivity extends Activity { private final Handler mLeakyHandler = new Hand ...
- [异常解决] MPU6050启动异常读出陀螺仪和加速度计的值全为0的解决办法
在调试一个自己做的手环,每次用keil烧写好程序运行的蓝牙.陀螺仪都是正常的.但是掉电再上电之后蓝牙是好的.陀螺仪可以读出ID但是读出的加速度和角速度数据全为0. 下面是发生问题时main函数的前面部 ...
- 5、CC2541芯片中级教程-OSAL操作系统(PWM+看门狗)
本文根据一周CC2541笔记汇总得来—— 适合概览和知识快速索引—— 全部链接: 中级教程-OSAL操作系统\OSAL操作系统-实验01 OSAL初探 [插入]SourceInsight-工程建立方法 ...
- js 倒计时实现
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- UWP入门教程1——UWP的前世今生
目录 引言 设备族群 UI 和通用输入模式 通用控件和布局面板 工具 自适应扩展 通用输入处理 引言 在本篇文章中,可以掌握以下知识: 设备族群,如何决定目标设备 新的UI控件和新面板帮助你适应不同的 ...
- Nginx+Keepalived(带Nginx监控脚本)
转载于:http://www.itxuexiwang.com/a/liunxjishu/2016/0220/151.html?1456381460 Keepalived+ nginx的安装部署 主机: ...
- 爱上MVC~为非法进行Action的用户提供HttpStatusCodeResult
回到目录 对一MVC来说,它有Controller和Action,其中Action用来为页面提供数据和相关逻辑,并最后将页面渲染出来,而有些action是需要一些参数的,如文章的最终页,可能需要一个I ...
- Beats数据采集---Packetbeat\Filebeat\Topbeat\WinlogBeat使用指南
Beats是elastic公司的一款轻量级数据采集产品,它包含了几个子产品: packetbeat(用于监控网络流量). filebeat(用于监听日志数据,可以替代logstash-input-fi ...