Swift学习笔记(10):类和结构体
目录:
- 基本
- 属性
- 方法
- 下标
- 继承
基本
使用class和struct关键字定义类和结构体。
・类是引用类型,结构体和枚举是值类型
・值类型被赋予给一个变量、常量或被传递给一个函数时,已值拷贝方式传递
・可以使用 === 或 !== 判断两个类实例引用是否指向同一个类实例
class SomeClass {
// 在这里定义类
}
struct SomeStructure {
// 在这里定义结构体
}
使用类或结构体名称加 ()类创建类或结构体实例,使用 . 操作符引用属性名。
结构体都带有自动生成的成员逐一构造器,用于初始化新结构体实例中成员的属性。新实例中各个属性的初始值可以通过属性的名称传递到成员逐一构造器之中。类没有默认的成员逐一构造器。
let vga = Resolution(width:, height: )
属性
属性将值跟特定的类、结构或枚举关联。存储属性存储常量或变量作为实例的一部分,而计算属性计算一个值。计算属性可以用于类、结构体和枚举,存储属性只能用于类和结构体。还可以定义属性观察器来监控属性值的变化。
・存储属性
存储属性可以是变量存储属性(用关键字 var 定义),也可以是常量存储属性(用关键字 let 定义)。可以在定义存储属性的时候指定默认值,也可以在构造过程中设置或修改存储属性的值,甚至修改常量存储属性的值。
struct FixedLengthRange {
var firstValue: Int
let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: , length: )
由于结构体属于值类型,当值类型的实例被声明为常量的时候,它的所有属性也就成了常量。属于引用类型的类则不同,把一个引用类型的实例赋给一个常量后,仍然可以修改该实例的变量属性。
延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用 lazy 来标示一个延迟存 储属性。必须将延迟存储属性声明成变量(使用 var 关键字),因为属性的初始值可能在实例构造完成之后才会得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
// DataImporter 是一个负责将外部文件中的数据导入的类。 这个类的初始化会消耗不少时间。
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")
// DataImporter 实例的 importer 属性还没有被创建
注意:如果一个被标记为 lazy 的属性在没有初始化时就同时被多个线程访问,则无法保证该属性只会被初始化一次。
・计算属性
计算属性不直接存储值,而是提供一个 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)
} // 如果计算属性的 setter 没有定义表示新值的参数名,
// 则可以使用默认名称 newValue
// set {
// origin.x = newValue.x - (size.width / 2)
// origin.y = newValue.y - (size.height / 2)
// }
set(newCenter) {
origin.x = newCenter.x - (size.width / )
origin.y = newCenter.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
}
}
・属性观察器
属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,即使新值和当前值相同的时候也不例外。可以为除了延迟存储属性之外的其他存储属性添加属性观察器,也可以通过重写属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器。
属性观察器包含:willSet 在新的值被设置之前调用; didSet 在新的值被设置之后立即调用。
class StepCounter {
var totalSteps: Int = {
willSet(newTotalSteps) {
print("About to set totalSteps to \(newTotalSteps)")
}
didSet {
// 默认值oldValue表示旧值的参数名
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps")
}
}
}
}
・类型属性
使用关键字 static 来定义类型属性。类型属性通过类型名加.操作符直接访问。在为类定义计算型类型属性时,可以改用关键字 class 来支持子类对父类的实现进行重写。
struct SomeStructure {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return
}
}
enum SomeEnumeration {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return
}
}
class SomeClass {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return
}
class var overrideableComputedTypeProperty: Int {
return
}
}
方法
实例方法和函数完全一致,定义在类中。每个实例都有一个隐含的 self 属性指向自己本身。
结构体和枚举是值类型。默认情况下,值类型的属性不能在它的实例方法中被修改。此时你可以使用 mutating 关键子修饰某个方法使其可以修改结构体或者枚举的属性;并且该方法对属性的修改都会反应到原始属性值上(即修改的是原始属性值),还可以给它隐含的 self 属性赋予一个全新的实例,这个新实例在方法结束时会替换现存实例。
struct Point {
var x = 0.0, y = 0.0
mutating func moveByX(deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY }
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveByX(2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))") // 打印 "The point is now at (3.0, 4.0)"
在可变方法中给 self 赋值。
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
self = Point(x: x + deltaX, y: y + deltaY)
}
}
枚举的可变方法可以把 self 设置为同一枚举类型中不同的成员:
enum TriStateSwitch {
case Off, Low, High
mutating func next() {
switch self {
case .Off:
self = .Low
case .Low:
self = .High
case .High:
self = .Off }
}
}
var ovenLight = TriStateSwitch.Low ovenLight.next()
// ovenLight 现在等于 .High ovenLight.next()
// ovenLight 现在等于 .Off
在类方法的 func 关键字之前加上关键字 static ,来指定类型方法,该类型方法通过类本身进行调用;类还可以用关键字 class 来允许子类重写父类的方法。
class SomeClass {
class func someTypeMethod() {
// 在这里实现类型方法
}
}
SomeClass.someTypeMethod()
在类型方法的方法体中, self 指向这个类型本身,而不是类型的某个实例。这意味着你可以用 self 来消除类型属性和类型方法参数之间的歧义。
下标
标可以定义在类、结构体和枚举中,是访问 合,列表或序列中元素的快捷方式。
定义下标使用 subscript 关键字,指定一个或多个输入参数和返回类型;与实例方法不同的是,下标可以设定为读写或只读。这种行为由 getter 和 setter 实现,有点类似计算型属性。
subscript(index: Int) -> Int {
get {
// 返回一个适当的 Int 类型的值
}
set(newValue) {
// 执行适当的赋值操作
}
}
下标可以接受任意数量任意类型的无默认值非输入输出参数,可以使用变量参数和可变参数;其返回值也可以是任意类型的。
一个类或结构体可以根据自身需要提供多个下标实现,使用下标时将通过入参的数量和类型进行区分,自动匹配合适的下标,这就是下标的重载。
struct Matrix {
let rows: Int, columns: Int
var grid: [Double]
init(rows: Int, columns: Int) {
self.rows = rows
self.columns = columns
grid = Array(count: rows * columns, repeatedValue: 0.0)
}
func indexIsValidForRow(row: Int, column: Int) -> Bool {
return row >= && row < rows && column >= && column < columns
}
subscript(row: Int, column: Int) -> Double {
get {
assert(indexIsValidForRow(row, column: column), "Index out of range")
return grid[(row * columns) + column]
}
set {
assert(indexIsValidForRow(row, column: column), "Index out of range")
grid[(row * columns) + column] = newValue
}
}
}
继承
一个类可以继承另一个类的方法,属性和其它特性。继承是类独有的特性,被继承的类叫超类,继承的类叫子类。
为了指明某个类的超类,将超类名写在子类名的后面,用冒号分隔:bsp;
class SomeClass: SomeSuperclass {
// 这里是子类的定义
}
可以通过关键字 override 重写子类继承来的实例方法,类方法,实例属性,或下标,定制自己的功能。
class Train: Vehicle {
// 重写父类Vehicle中的makeNoise方法
override func makeNoise() {
print("Choo Choo")
}
}
可以通过 super 关键字应用超类对象。
你可以重写继承来的实例属性或类型属性,提供自己定制的 getter 和 setter,或添加属性观察器使重写的属性可以观察属性值什么时候发生变化。
你可以将一个继承来的只读属性重写为一个读写属性,只需要在重写版本的属性里提供 getter 和 setter 即可。但是,你不可以将一个继承来的读写属性重写为一个只读属性。
你可以通过重写属性为一个继承来的属性添加属性观察器。这样一来,当继承来的属性值发生改变时,你就会被 通知到,无论那个属性原本是如何实现的。
・ 你不可以为继承来的常量存储型属性或继承来的只读计算型属性添加属性观察器。这些属性的值不可以被设置 的,所以,为它们提供 willSet 或 didSet 实现是不恰当
・ 你不可以同时提供重写的 setter 和重写的属性观察器。如果你想观察属性值的变化,并你已 经为那个属性提供了定制的 setter,那么你在 setter 中就可以观察到任何值变化了
你可以通过把方法,属性或下标标记为 final 来防止它们被重写
声明:该系列内容均来自网络或电子书籍,只做学习总结!
Swift学习笔记(10):类和结构体的更多相关文章
- swift学习笔记3——类、结构体、枚举
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- swift学习笔记之-类和结构体
//类和结构体 import UIKit //类和结构体 /* 1.枚举enum.结构体struct和String.Array.Dictionary类型,都属于值传递类型,被赋值给新的常量或变量时传递 ...
- Swift学习笔记(11)--类与结构体
类与结构是编程人员在代码中会经常用到的代码块.在类与结构中可以像定义常量,变量和函数一样,定义相关的属性和方法以此来实现各种功能. 和其它的编程语言不太相同的是,Swift不需要单独创建接口或者实现文 ...
- 【Swift】学习笔记(八)——类和结构体
1.类和结构体的定义 <pre name="code" class="html">struct Resolution { var width = 0 ...
- 【c# 学习笔记】类与结构体的区别
由于类与结构体在语法和使用上都非常类似,导致我们这些初学者容易混淆.为更好理解,特做以下区分记录: ① 语法上的区别在于,定义类要使用关键词class,而定义结构体则使用关键词struct. ② 结构 ...
- Swift学习笔记:类和结构
一.类和结构的异同 类和结构有一些相似的地方.它们都能够: 1. 定义一些能够赋值的属性: 2. 定义具有功能性的方法 3. 定义下标.使用下标语法 4. 定义初始化方法来设置初始状态 5. 在原实现 ...
- swift 学习- 10 -- 类和结构体
// '类和结构体' 是人们构建代码所使用的一种通用且灵活的构造体, 我们可以使用完全相同的语法规则来为 '类和结构体' 定义属性 (变量 和 常量) 和添加方法, 从而扩展 类和结构体 的功能 // ...
- 【Swift学习】Swift编程之旅---类和结构体(十三)
与其他编程语言所不同的是,Swift 并不要求你为自定义类和结构去创建独立的接口和实现文件.你所要做的是在一个单一文件中定义一个类或者结构体,系统将会自动生成面向其它代码的外部接口. 注意:通常一个类 ...
- Bash脚本编程学习笔记07:循环结构体
本篇中涉及到算术运算,使用了$[]这种我未在官方手册中见到的用法,但是确实可用的,在此前的博文<Bash脚本编程学习笔记03:算术运算>中我有说明不要使用,不过自己忘记了.大家还是尽量使用 ...
- Bash脚本编程学习笔记06:条件结构体
简介 在bash脚本编程中,条件结构体使用if语句和case语句两种句式. if语句 单分支if语句 if TEST; then CMD fi TEST:条件判断,多数情况下可使用test命令来实现, ...
随机推荐
- CZLayer的阴影
CALayer有一个shadow属性 意思是阴影 shadowcolor //颜色 shadowoffset //偏移 shadowOpacity //透明度 layer有一个方法 mas ...
- Spark Streaming概念学习系列之Spark Streaming的竞争对手
不多说,直接上干货! Spark Streaming的竞争对手 Storm 在Storm中,先要设计一个用于实时计算的图状结构,我们称之为拓扑(topology).这个拓扑将会被提交给集群,由集群中的 ...
- Struts2简单环境搭建
一.开篇 Struts2是一个运行于web容器的表示层框架,其核心作用是帮助我们处理Http请求.Struts2处理Http请求(Request),并进行内部处理,再进行Http返回. 下载strut ...
- 一个javascript面试题解析
; function fn(){ console.log(this.length); } var obj = { length: , method: function (fn) { fn(); // ...
- TortoiseSVN—Repo-browser
TortoiseSVN—Repo-browser,打开你要比较的两个版本所在的地址,选择一个版本做为比较的基础(单击右键—选择mark for comparison),再选择另外一个版本(单击右键—选 ...
- vue中slot的用法案例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Mac-O文件加载的全过程(一)
在Mac的开发中, 有没有想过当我们点击可执行文件之后,Mac究竟做了什么事情才让我们的程序运行起来? 对于应用层开发人员或者普通的用户而言, 其实无需知道的这么详细:但是对于内核开发人员而言, 如果 ...
- Kattis - mixedfractions
Mixed Fractions You are part of a team developing software to help students learn basic mathematics. ...
- Shell(五)Shell输入/输出重定向
Shell 输入/输出重定向 大多数 UNIX 系统命令从你的终端接受输入并将所产生的输出发送回到您的终端.一个命令通常从一个叫标准输入的地方读取输入,默认情况下,这恰好是你的终端.同样,一个命令 ...
- Lvs+heartbeat高可用高性能web站点的搭建
这是我们公司在实际的生产环境当中使用的一套东西,希望对大家有所帮助(实际的公网ip,我已经做了相应的修改): 说明:每台服务器需要有两块网卡:eth0连接内网的交换机,用私网ip,实现服务器间内部访问 ...