目录:

  • 基本
  • 属性
  • 方法
  • 下标
  • 继承

基本

使用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):类和结构体的更多相关文章

  1. swift学习笔记3——类、结构体、枚举

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  2. swift学习笔记之-类和结构体

    //类和结构体 import UIKit //类和结构体 /* 1.枚举enum.结构体struct和String.Array.Dictionary类型,都属于值传递类型,被赋值给新的常量或变量时传递 ...

  3. Swift学习笔记(11)--类与结构体

    类与结构是编程人员在代码中会经常用到的代码块.在类与结构中可以像定义常量,变量和函数一样,定义相关的属性和方法以此来实现各种功能. 和其它的编程语言不太相同的是,Swift不需要单独创建接口或者实现文 ...

  4. 【Swift】学习笔记(八)——类和结构体

    1.类和结构体的定义 <pre name="code" class="html">struct Resolution { var width = 0 ...

  5. 【c# 学习笔记】类与结构体的区别

    由于类与结构体在语法和使用上都非常类似,导致我们这些初学者容易混淆.为更好理解,特做以下区分记录: ① 语法上的区别在于,定义类要使用关键词class,而定义结构体则使用关键词struct. ② 结构 ...

  6. Swift学习笔记:类和结构

    一.类和结构的异同 类和结构有一些相似的地方.它们都能够: 1. 定义一些能够赋值的属性: 2. 定义具有功能性的方法 3. 定义下标.使用下标语法 4. 定义初始化方法来设置初始状态 5. 在原实现 ...

  7. swift 学习- 10 -- 类和结构体

    // '类和结构体' 是人们构建代码所使用的一种通用且灵活的构造体, 我们可以使用完全相同的语法规则来为 '类和结构体' 定义属性 (变量 和 常量) 和添加方法, 从而扩展 类和结构体 的功能 // ...

  8. 【Swift学习】Swift编程之旅---类和结构体(十三)

    与其他编程语言所不同的是,Swift 并不要求你为自定义类和结构去创建独立的接口和实现文件.你所要做的是在一个单一文件中定义一个类或者结构体,系统将会自动生成面向其它代码的外部接口. 注意:通常一个类 ...

  9. Bash脚本编程学习笔记07:循环结构体

    本篇中涉及到算术运算,使用了$[]这种我未在官方手册中见到的用法,但是确实可用的,在此前的博文<Bash脚本编程学习笔记03:算术运算>中我有说明不要使用,不过自己忘记了.大家还是尽量使用 ...

  10. Bash脚本编程学习笔记06:条件结构体

    简介 在bash脚本编程中,条件结构体使用if语句和case语句两种句式. if语句 单分支if语句 if TEST; then CMD fi TEST:条件判断,多数情况下可使用test命令来实现, ...

随机推荐

  1. 算法入门经典第七章 例题7-2-1 生成1-n的排列

    输入正数n,按字典序从小到大的顺序输出n个数的所有排列.两个序列的字典序大小关系等价于从头开始第一个不相同位置处的大小关系. 递归的边界应该很好理解吧,当集合s[]中没有一个元素的时候,按照上面的伪码 ...

  2. 跨域-jsonp、cors、iframe、document.domain、postMessage()

    同源策略 概念:同源: 协议.域名.端口号 完全相同 同源策略是浏览器的一种安全策略:且浏览器不会将违反同源策略的响应信息返回 http://127.0.0.1:3000/index.html     ...

  3. 关于获取WebForm控件的问题

    遇到这样的一个问题: 在GridView加载了数据之后,GridView的个别列被设置为TextBox单元格,就是可以修改数量了,单价什么的: 这样就触发了TextChanged事件: 现在要记录谁修 ...

  4. java 读写分离

    源码地址:http://git.oschina.net/xiaochangwei 先回答下 1.为啥要读写分离? 大家都知道最初开始,一个项目对应一个数据库,基本是一对一的,但是由于后来用户及数据还有 ...

  5. WCF(一)控制台寄宿

    WCF是微软开发的一款通信框架.具有跨平台跨操作系统的特点,所以,WCF一般用于开发第三方接口或者在分布式系统用做数据交互. WCF三要素分别是地址(Address).绑定(Binding).契约(C ...

  6. Unity 已下载工程包存放路径

    Mac Finder 中 Shift+Command+G输入后回车 ~/Library/Unity/Asset Store-5.x Windows 么有,自己上别的网站查去~

  7. C# 正则表达式大全(转载)

    文章导读 正则表达式的本质是使用一系列特殊字符模式,来表示某一类字符串.正则表达式无疑是处理文本最有力的工具,而.NET提供的Regex类实现了验证正则表达式的方法.Regex 类表示不可变(只读)的 ...

  8. Long型转换成IP段String、StringIP段转换成Long型

    /** 把long类型的Ip转为一般Ip类型:xx.xx.xx.xx * * @param ip * @return */ public static String getIpFromLong(Lon ...

  9. 存储过程(带有逻辑的sql语句)

    -- 创建存储过程 DELIMITER $       -- 声明存储过程的结束符 CREATE PROCEDURE pro_test()           --存储过程名称(参数列表) BEGIN ...

  10. You-Dont-Need-JQuery (你不需要JQuery)

    看完这篇文章我才觉得真的要用JQuery ,因为实在是有些地方设计的使用太复杂了, document.querySelector() 和 Document.querySelectorAll 的确是很方 ...