Swift 学习笔记 (属性)
属性可以将值与特定的类 结构体 或者枚举联系起来。 存储属性会存储常量或者变量作为实例的一部分。反之计算属性会计算(而不是存储值)值。 计算属性可以由类 结构体 和枚举定义。存储属性只能由类和结构体定义。
存储属性和计算属性通常和特定类型的实例相关联。总之 属性也可以与类型本身相关联。这中属性就是所谓的类型属性。
另外,你也可以定义属性观察器来检查属性中值的变化,这样你就可以用自定义的行为来响应。属性观察器可以被添加到你自己定义的存储属性中,也可以添加到子类从他的父类那里所继承来的属性中。
存储属性
在其最简单的形式下,存储属性是一个作为特定类和结构体实例一部分的常量或者变量。存储属性要么是变量存储属性(var 声明)要么是常量存储属性(let 声明)
下面的例子定义了一个名为 FixedLengthRange 的结构体,它描述了一个一旦被创建长度就不能改变的整型值域:
struct FixedLengthRange {
var firstValue:Int
let length:Int
}
FixedLengthRange的实例有一个名为firstValue的变量存储属性和一个名为length的常量存储属性。在上面的例子中,当新的值域创建时length已经被创建并且不能再修改,因为这是一个常量属性。
常量结构体实例的存储属性
如果你创建了一个结构体实例并且把这个实例赋给常量,你不能修改这个实例的属性,即使是声明为变量的属性。
let rangeOfFourItems = FixedLengthRange(firstValue: , length: ) //rangeOfFourItems.firstValue = 2//不能修改会报错
延迟存储属性
延迟存储属性的初始值在其第一次使用时才进行计算。你可以通过在其声明前标注lazy修饰语来表示一个延迟存储属性。
你必须把延迟存储属性声明为变量(使用 var 关键字),因为它的初始值可能在实例初始化完成之前无法取得。常量属性则必须在初始化完成之前有值,因此不能声明为延迟。
一个属性的初始值可能依赖于某些外部因素,当这些外部因素的值只有在实例的初始化完成后才能得到时,延迟属性就可以发挥作用了。而当属性的初始值需要执行复杂或代价高昂的配置才能获得,你又想要在需要时才执行,延迟属性就能够派上用场了。
class dataImporter {
var fileName = "data.txt"
}
class dataManager {
lazy var importer = dataImporter()
var data = [String]()
}
let manager = dataManager()
manager.data.append("some data")
manager.data.append("some more data")
类 DataManager 有一个名为 data 的存储属性,它被初始化为一个空的新 String 数组。尽管它的其余功能没有展示出来,还是可以知道类 DataManager 的目的是管理并提供访问这个 String 数组的方法。
DataManager 类的功能之一是从文件导入数据。此功能由 DataImporter 类提供,它假定为需要一定时间来进行初始化。这大概是因为 DataImporter 实例在进行初始化的时候需要打开文件并读取其内容到内存中。
DataManager 实例并不要从文件导入数据就可以管理其数据的情况是有可能发生的,所以当 DataManager 本身创建的时候没有必要去再创建一个新的 DataImporter 实例。反之,在 DataImporter 第一次被使用的时候再创建它才更有意义。
因为它被 lazy 修饰符所标记,只有在 importer 属性第一次被访问时才会创建 DataManager 实例,比如当查询它的 fileName 属性时:
print(manager.importer.fileName)
存储属性与实例变量
如果你有 Objective-C 的开发经验,那你应该知道在类实例里有两种方法来存储值和引用。另外,你还可以使用实例变量作为属性中所储存的值的备份存储。
Swift 把这些概念都统一到了属性声明里。Swift 属性没有与之相对应的实例变量,并且属性的后备存储不能被直接访问。这避免了不同环境中对值的访问的混淆并且将属性的声明简化为一条单一的、限定的语句。所有关于属性的信息——包括它的名字,类型和内存管理特征——都作为类的定义放在了同一个地方。
计算属性
除了存储属性,类、结构体和枚举也能够定义计算属性,而它实际并不存储值。相反,他们提供一个读取器和一个可选的设置器来间接得到和设置其他的属性和值。
struct Point {
var x = 0.0
var y = 0.0
} struct Size {
var width = 0.0
var 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)
square.origin.x
square.origin.y
只读计算属性
一个有读取器但是没有设置器的计算属性就是所谓的只读计算属性。只读计算属性返回一个值,也可以通过点语法访问。但是不能被修改为另外一个值。
你必须用 var 关键字定义计算属性——包括只读计算属性——为变量属性,因为它们的值不是固定的。 let 关键字只用于常量属性,用于明确那些值一旦作为实例初始化就不能更改。
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)
print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
属性观察者
属性观察者会观察并对属性值的变化做出回应。每当一个属性的值被设置时,属性观察者都会被调用,即使这个值与该属性当前的值相同。
你可以为你定义的任意存储属性添加属性观察者,除了延迟存储属性。你也可以通过在子类里重写属性来为任何继承属性(无论是存储属性还是计算属性)添加属性观察者。
willSet 会在该值被存储之前调用
didSet 会在一个新值被存储后调用
class LightBuld {
//类变量 不能通过实例引用
static let maxCurrent =
var current = {
didSet (oldCurrent){
if current > LightBuld.maxCurrent {
//current = 修改之前的值
current = oldCurrent
print("功率过大")
}else if < current && current <= {
print("功率适中")
}else {
print("不符合实际情况")
}
}
}
}
let buld = LightBuld()
buld.current =
class LightBuld {
//类变量 不能通过实例引用
static let maxCurrent =
var current = {
//在赋值之前运行的逻辑 newCurrent 将要被赋值的数据
willSet (newCurrent){
print("变化了 \(abs(newCurrent - current))")
} didSet (oldCurrent){
if current > LightBuld.maxCurrent {
//current = 修改之前的值
current = oldCurrent
print("功率过大")
}else if < current && current <= {
print("功率适中")
}else {
print("不符合实际情况")
}
}
}
}
let buld = LightBuld()
buld.current =
buld.current =
如果我们不在willSet 和 didSet后面的括号中声明变量名称,可以使用系统默认的 对于willSet来说是 newValue 对于didSet来说是oldVlaue。
enum Theme {
case DayModel
case NightModel
}
class UI {
var fontColor:UIColor!
var backGroundColor:UIColor!
var themeModel:Theme {
didSet {
self.changeModel(themeModel: themeModel)
}
} init(themeModel:Theme) {
self.themeModel = themeModel
self.changeModel(themeModel: themeModel)
} func changeModel(themeModel:Theme) {
switch themeModel {
case .DayModel:
fontColor = UIColor.black
backGroundColor = UIColor.white
case .NightModel:
fontColor = UIColor.white
backGroundColor = UIColor.black
}
}
}
//注意 didSet 和 willSet不会在初始化阶段 也就是init阶段调用的 包括有默认值的时候 也不会调用
let ui = UI(themeModel: .DayModel)
ui.fontColor
ui.backGroundColor ui.themeModel = .NightModel
ui.fontColor
ui.backGroundColor
全局和局部变量
上边描述的计算属性和观察属性的能力同样对全局变量和局部变量有效。全局变量是定义在任何函数、方法、闭包或者类型环境之外的变量。局部变量是定义在函数、方法或者闭包环境之中的变量。
类型属性
实例属性是属于特定类型实例的属性。每次你创建这个类型的新实例,它就拥有一堆属性值,与其他实例不同。
你同样可以定义属于类型本身的属性,不是这个类型的某一个实例的属性。这个属性只有一个拷贝,无论你创建了多少个类对应的实例。这样的属性叫做类型属性。
存储类型属性可以是变量或者常量。计算类型属性总要被声明为变量属性,与计算实例属性一致。
类型属性语法
class Player {
var name:String
var score = 0
//类属性
static var highestScore =
init(name:String) {
self.name = name
}
func play() {
let score:Int = Int(arc4random()%)
print("\(name) played and got \(score) scores")
self.score += score
print("Total score of \(name) is \(self.score)") if self.score > Player.highestScore {
Player.highestScore = self.score
}
print("所有玩家的最高分是\(Player.highestScore)")
}
}
let player1 = Player(name: "player1")
let player2 = Player(name: "player2") player1.play()
player2.play()
player2.play()
类方法
通过在func前添加static 可以声明一个类方法 在类(class)中也可以使用关键字class 达到同样的目的
struct Matrix {
var m:[[Int]]
var row:Int
var col:Int init?(_ arr2d:[[Int]]) {
guard arr2d.count > else {
return nil
}
let row = arr2d.count
let col = arr2d[].count
for i in ..<row {
if arr2d[i].count != row {
return nil
}
}
self.m = arr2d
self.row = row
self.col = col
} func printMatrix() {
for i in ..<row {
for j in ..<col {
print(m[i][j],terminator:"\t")
}
print()
}
} static func identityMatrix(n:Int) ->Matrix?{
if n <= {
return nil
}
var arr2d:[[Int]] = []
for i in ..<n {
var row = [Int](repeatElement(, count: n))
row[i] = ;
arr2d.append(row);
}
return Matrix(arr2d)
}
} if let m = Matrix([[,],[,]]) {
m.printMatrix()
} if let e = Matrix.identityMatrix(n: ) {
e.printMatrix()
}
Swift 学习笔记 (属性)的更多相关文章
- 【swift学习笔记】二.页面转跳数据回传
上一篇我们介绍了页面转跳:[swift学习笔记]一.页面转跳的条件判断和传值 这一篇说一下如何把数据回传回父页面,如下图所示,这个例子很简单,只是把传过去的数据加上了"回传"两个字 ...
- Swift学习笔记(一)搭配环境以及代码运行成功
原文:Swift学习笔记(一)搭配环境以及代码运行成功 1.Swift是啥? 百度去!度娘告诉你它是苹果最新推出的编程语言,比c,c++,objc要高效简单.能够开发ios,mac相关的app哦!是苹 ...
- swift学习笔记5——其它部分(自动引用计数、错误处理、泛型...)
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- swift学习笔记4——扩展、协议
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- swift学习笔记3——类、结构体、枚举
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- swift学习笔记1——基础部分
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- 记录:swift学习笔记1-2
swift还在不断的更新做细微的调整,都说早起的鸟儿有虫吃,那么我们早点出发吧,趁着国内绝大多数的coder们还没有开始大范围普遍应用. 网上有些大神说:swift很简单!我不同意这个观点,假如你用h ...
- swift学习笔记2——函数、闭包
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- Swift学习笔记一
最近计划把Swift语言系统学习一下,然后将MagViewer用这种新语言重构一次,并且优化一下,这里记录一下Swift的学习笔记. Swift和Objective-C相比,在语法和书写形式上做了很多 ...
随机推荐
- IT人为了自己父母和家庭,更得注意自己的身体和心理健康
我前一阵在一家互联网公司,工作节奏是995,忙的时候,要晚上10点才能离开公司,有时候周六还得加班.自己感觉身体状况有所下降,且听说其它一个组,在体检后多少都查出问题来,细思极恐. 有时候确实忙,那么 ...
- 洛谷——P1617 爱与愁的一千个伤心的理由
P1617 爱与愁的一千个伤心的理由 题目背景 (本道题目隐藏了两首歌名,找找看哪~~~) <爱与愁的故事第一弹·heartache>第二章. 经历了心痛后,爱与愁大神不行了. 题目描述 ...
- ASIHTTPRequest 类库在iOS 7.0中,会有一些报错警告,需要稍作修改
1. if ([inputStream streamStatus] == NSStreamEventErrorOccurred) { 修改成: if ([inputStream streamStatu ...
- 【DQ冰淇淋】—— Babylon 冰淇淋三维互动营销项目总结
前言:在学习过Babylon.js基础之后,我上手的第一个网页端3D效果制作项目就是‘DQ冰淇淋’.这个小项目应用到了Babylon最基础的知识,既可以选味道,选点心,也可以旋转.倒置冰淇淋,互动起来 ...
- oracle软件安装完毕之后,如何创建数据库
oracle软件安装完毕之后,如何创建数据库 学习了:https://zhidao.baidu.com/question/1800966379896476147.html 使用了Database Co ...
- 粗略。。Java项目设计模式之笔记----studying
设计模式 设计模式:解决这个问题的一种行之有效的思想. 设计模式:用于解决特定环境下.反复出现的特定问题的解决方式. 设计模式学习概述 ★ 为什么要学习设计模式 1.设计模式都是一些相对优秀的解决方式 ...
- 微信小程序 - 考试前三排名实现
实现原理:利用背景图片以及nth-child实现
- 各类免费的API接口分享,无限次
各类免费的API接口分享: 手机号码归属地API:https://www.juhe.cn/docs/api/id/11 历史上的今天API:https://www.juhe.cn/docs/api/i ...
- Vue 响应式属性
本文参考自:https://www.w3cplus.com/vue/vue-reactivity-and-pitfalls.html 1.概述 当创建一个Vue实例时,每个数据属性.组件属性等都是可以 ...
- Codeforces Round #243 (Div. 2)——Sereja and Table
看这个问题之前,能够先看看这个论文<一类算法复合的方法>,说白了就是分类讨论,可是这个思想非常重要 题目链接 题意: 首先给出联通块的定义:对于相邻(上下和左右)的同样的数字视为一个联通块 ...