Swift学习笔记十二
方法
方法就是和某种特定类型相关联的函数。类、结构体、枚举都可以定义实例方法和类型方法。类型方法和OC中的类方法类似。
结构体和枚举也可以定义方法是Swift与C/OC之间很大的一个区别,在OC中,只有类才能定义方法。
实例方法
实例方法是从属于某个类实例或结构体实例、枚举实例的方法。他们提供与该实例相关的功能,比如获取更改属性或者提供其他函数功能。实例方法的语法和函数完全相同。
实例方法隐式地可以访问该类型的属性和方法。只能从该类型的实例上调用实例方法。比如:
class Counter {
var count =
func increment() {
count++
}
func incrementBy(amount: Int) {
count += amount
}
func reset() {
count =
}
} let counter = Counter()
// the initial counter value is 0
counter.increment()
// the counter's value is now 1
counter.incrementBy()
// the counter's value is now 6
counter.reset()
// the counter's value is now 0
方法的内部和外部参数名称
如前所述,函数的参数可以同时拥有内部名称和外部名称,方法也是如此。不过,实例方法的内部和外部名称的默认行为和函数有所不同。
像OC一样,Swift中方法的名字一般都是用一个介词如with、for、by和第一个参数名称接应起来的。比如上个例子中的incrementBy(_:),介词使得方法在被调用的时候可读性更高,就像一个连贯的句子一样。因此Swift通过给方法参数提供了不同于函数的默认行为来使得这种方法命名方式更加便利:Swift给方法的第一个参数名提供了内部参数名,给第二个及以后的所有参数名同时提供了内部和外部参数名。
依旧以上一个Counter为例子,假设它的实例方法incrementBy需要两个参数:
class Counter {
var count: Int =
func incrementBy(amount: Int, numberOfTimes: Int) {
count += amount * numberOfTimes
}
}
默认情况下,Swift把第一个参数名amount只看做内部参数名,而把numberOfTimes同时看做内部和外部变量名。因此,在调用这个实例方法的时候:
let counter = Counter()
counter.incrementBy(, numberOfTimes: )
// counter value is now 15
不需要给方法的第一个参数定义外部参数名,因为它的意义通过方法名incrementBy可以很明确地表现出来,但是后边的参数都需要外部参数名使得在方法调用的时候语义非常明确。这种默认的处理方式就像你在方法定义的时候已经在第二个及以后的每个参数名称前加上了(#)符号。
当然,如果你希望改变这种默认行为,给第一个参数指定外部参数名,也可以用通常的方法指定,如果你不想给第二个及以后的参数添加默认外部参数名,那么可以在参数名前加上下划线(_)作为外部参数名。
self属性
每个实例对象都有一个隐式属性self,它指向实例对象本身。在实际开发中,并不需要经常写self,在实例方法内部,如果你不显示地写明self,每次你在使用一直的属性或方法时,Swift都假定你是在用当前对象的属性或方法。这个原则的一个主要例外是当方法的参数名和实例对象的属性名相同时,方法的参数名会具有较高的优先级,如果需要使用实例对象的属性,就需要使用self。
从实例方法内改变值类型
结构体和枚举都是值类型的,默认情况下,值类型的属性是不能从它的实例方法内部改变的。
但是,如果你希望从一个特殊的方法里边改变结构体或枚举的属性值,你可以选择改变那个方法的行为。然后方法就可以从内部改变它的属性,并且它产生的任何改变在方法结束后都会写到原始的结构体上。方法还可以给它的隐式属性self赋一个全新的实例对象,当方法结束时,这个新实例将取代现有的那个。
通过在func前加上关键字mutating来实现上面的行为:
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)
println("The point is now at (\(somePoint.x), \(somePoint.y))")
// prints "The point is now at (3.0, 4.0)”
上面的示例中,定义了一个mutating方法moveByX,它的目的是将点对象移动一定距离,它是在当前的点对象上直接操作的,而不是返回一个新的点对象。
注意,如果你将值类型实例对象赋值给了一个常量,那你就不能调用它的mutating方法了,因为一旦赋值给常量,它的所有属性就都不能改变了,即使该属性是变量属性。
从Mutating方法内部给self赋值
Mutating方法可以给隐式属性self赋一个全新的对象,比如上面的例子可以改写成:
struct Point {
var x = 0.0, y = 0.0
mutating func moveByX(deltaX: Double, y deltaY: Double) {
self = Point(x: x + deltaX, y: y + deltaY)
}
}
这个方法是返回了一个全新点对象实例,不过当方法完成时,结果和前面的例子是完全一样的。
枚举类型的Mutating方法可以将隐式属性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 is now equal to .High
ovenLight.next()
// ovenLight is now equal to .Off
类型方法
如前所述,实例方法就是在实例对象上调用的方法。而类型方法是指从类型本身调用的方法。通过在func前面加上关键字static来声明类型方法。类也可以用class关键字来允许子类可以重载父类对该方法的实现。
在OC中,只能在类上声明类型方法,而在Swift中,可以在类、结构体、枚举上声明类型方法。各种类型方法都显示地标明它支持的类型。
class SomeClass {
class func someTypeMethod() {
// type method implementation goes here
}
}
SomeClass.someTypeMethod()
在类型方法内部,隐式属性self指向类型本身,而非它的实例对象。对结构体和枚举而言,这意味着当类型属性名和方法参数名相同的时候可以用来做区分。
通常情况下,在类型方法里边出现的未定义的方法和属性名字都会指向这个类型的类型属性和类型方法,不需要在属性和方法名字前加类型名称前缀。
下标
下标是获取集合、列表或者队列中元素的简便方法,下标可以通过索引序列(index)来获取和存储值,而不需要额外获取和设置方法。
类、结构和枚举可以定义下标,你可以为一个类型定义多个下标,下标也不局限于一维,可以定义具有多个参数的下标。
下标语法
下标语法通过在实例名称后面写上包含一个或多个值的中括号来使你可以查询实例对象。语法和实例方法语法及计算式属性语法都很像。通过subscript关键字来定义下标,然后像实例方法那样指定一个或多个输入参数及返回类型。和实例方法不同的是,下标可以是只读的活着是读写的。这个行为和计算式属性的getter和setter相似:
subscript(index: Int) -> Int {
get {
// return an appropriate subscript value here
}
set(newValue) {
// perform a suitable setting action here
}
}
这个setter和计算式属性类似的,如果你指定了新值参数名,则用那个名字,如果没有指定,默认提供的是newValue。
如果是只读下标,就去掉setter,和计算式属性类似,只有getter时可以省略get关键字用简写形式。
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
let threeTimesTable = TimesTable(multiplier: )
println("six times three is \(threeTimesTable[6])")
// prints "six times three is 18”
下标可以接受任意数目的任意类型的参数,也可以返回任意类型的返回值。下标可以使用变量参数以及可变参数,但是不能使用in-out参数,也不能给参数提供默认值。
类和结构体可以根据需要提供多种下表实现方式。至于哪种方式会被使用,取决于在使用下标的时候,方括号内参数类型,这也叫做下标重载。
下标通常都是接受一个参数,当然,也可以定义为接受多个参数:
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
}
}
}
var matrix = Matrix(rows: 2, columns: 2)
matrix[0, 1] = 1.5
matrix[1, 0] = 3.2
继承
一个类可以从另一个类继承方法,属性或者其他特性,继承的类叫子类,被继承的类叫超类。继承是类区别于其他类型的一个主要特征。
类可以访问它超类的属性、方法和下标,也可以提供自己对这些属性、方法和下标的重载版本来改变它们的行为。类也可以给继承的属性添加属性观察者,无论这个属性在超类中是存储式属性还是计算式属性。
任何不继承自其他类的类被称为基类。Swift中的类并没有统一继承自某个全局基类,如果你创建的类没有继承自任何类,它就是基类。
class Vehicle {
var currentSpeed = 0.0
var description: String { //这是一个只读的计算式属性
return "traveling at \(currentSpeed) miles per hour"
}
func makeNoise() {
// do nothing - an arbitrary vehicle doesn't necessarily make a noise
}
}
这里定义了一个没有继承自任何类的基类,它的一个实例方法并没有实现,这是留给子类去具体实现的。
子类的定义是在类名后边加上冒号,然后加上超类的名称:
class Bicycle: Vehicle {
var hasBasket = false
}
子类默认就继承了超类的特性,比如Bicycle类就自动有currentSpeed属性及makeNoise方法等。当然,子类还可以定义自己的属性和方法,子类也可以被再次继承,子类会依次获得继承链上那些超类的特性。
重载
子类可以给继承来的实例方法、类型方法、实例属性、类型属性及下标提供自己的实现版本,否则它们的实现方式就是继承自超类的。这叫做重载。
在重载实现前面加上关键字override来标明重载某个特性,这表示你是有意要重载某个特性,而不是不小心用了同样的名称或定义。事实上,任何不带override关键字的重载都会在编译时触发错误。override关键字也会让Swift检查重载是否和超类中的特性匹配,以确保重载的定义是正确的。
有时候,在子类重载超类特性的时候,可能需要访问超类对该类的实现,这通过super前缀来访问超类的属性、方法及下标实现。
重载方法就是在方法的func前加上override关键字.
任何继承来的属性都可以被重载,你可以提供自定义的getter,需要的时候也可以提供自定义的setter,无论这个属性在超类中是定义为存储属性或是计算属性。超类中属性究竟是存储式还是计算式子类是无法知道的,它只知道这个属性的名字和类型。你必须同时写明重载的属性的名称和类型以便Swift检查重载是否正确。你可以通过提供getter和setter将一个只读的属性在子类中重载为读写的属性,然后,你不能将一个可读写的属性重载为只读的。
注意:如果你重载的时候提供了setter,那么你必须同时提供getter作为重载的一部分。
class Car: Vehicle {
var gear =
override var description: String {
return super.description + " in gear \(gear)"
}
}
你可以通过属性重载来给继承来的属性添加观察者,无论这个属性最初是如何实现和定义的,在它发生改变的时候你都可以收到通知。
注意:你不能给继承来的常量存储属性或者只读的计算属性添加观察者,这些属性是不能被改变的,因此在重载时提供willSet和didSet是不合适的。并且,你也不能同时重载一个属性的setter和它的观察者,因为如果你重载了setter,你可以直接在setter里边实现观察者的目的。
class AutomaticCar: Car {
override var currentSpeed: Double {
didSet {
gear = Int(currentSpeed / 10.0) +
}
}
} let automatic = AutomaticCar()
automatic.currentSpeed = 35.0
println("AutomaticCar: \(automatic.description)")
// AutomaticCar: traveling at 35.0 miles per hour in gear 4
阻止重载
你可以通过标明最终版本来阻止方法、属性或下标被重载,在他们关键字前加上final关键字即可,比如:final var, final func, final class func, final subscript等。
任何试图重载已经标记为final的特性都会触发编译时错误。
你也可以在类关键字class前加上final关键字来将整个类标记为最终版本,任何试图继承final类都会触发编译时错误。
Swift学习笔记十二的更多相关文章
- python3.4学习笔记(十二) python正则表达式的使用,使用pyspider匹配输出带.html结尾的URL
python3.4学习笔记(十二) python正则表达式的使用,使用pyspider匹配输出带.html结尾的URL实战例子:使用pyspider匹配输出带.html结尾的URL:@config(a ...
- Go语言学习笔记十二: 范围(Range)
Go语言学习笔记十二: 范围(Range) rang这个关键字主要用来遍历数组,切片,通道或Map.在数组和切片中返回索引值,在Map中返回key. 这个特别像python的方式.不过写法上比较怪异使 ...
- 【swift学习笔记】二.页面转跳数据回传
上一篇我们介绍了页面转跳:[swift学习笔记]一.页面转跳的条件判断和传值 这一篇说一下如何把数据回传回父页面,如下图所示,这个例子很简单,只是把传过去的数据加上了"回传"两个字 ...
- java jvm学习笔记十二(访问控制器的栈校验机制)
欢迎装载请说明出处:http://blog.csdn.net/yfqnihao 本节源码:http://download.csdn.net/detail/yfqnihao/4863854 这一节,我们 ...
- (C/C++学习笔记) 十二. 指针
十二. 指针 ● 基本概念 位系统下为4字节(8位十六进制数),在64位系统下为8字节(16位十六进制数) 进制表示的, 内存地址不占用内存空间 指针本身是一种数据类型, 它可以指向int, char ...
- Python学习笔记(十二)—Python3中pip包管理工具的安装【转】
本文转载自:https://blog.csdn.net/sinat_14849739/article/details/79101529 版权声明:本文为博主原创文章,未经博主允许不得转载. https ...
- Swift学习笔记(二十二)——字典的基本操作
(1)计算字典长度 . (2)推断字典是否为空 . (3)查询字典元素 . (4)取出字典元素进行拼接 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/fo ...
- Swift学习笔记十
枚举 一个枚举为一组相关联的值定义一个通用类型,并且让你可以在代码中类型安全地操作这些值. C中的枚举将关联的名字指派给一系列整型值.Swift中的枚举类型更为活泼,并不需要为每个成员指定值,如果指定 ...
- Swift学习笔记十六:协议
Protocol(协议)用于统一方法和属性的名称,而不实现不论什么功能. 协议可以被类.枚举.结构体实现.满足协议要求的类,枚举,结构体被称为协议的遵循者. 遵循者须要提供协议指定的成员,如属性,方法 ...
随机推荐
- hdu 2602 Bone Collector(01背包)
题意:给出包裹的大小v,然后给出n块骨头的价值value和体积volume,求出一路下来包裹可以携带骨头最大价值 思路:01背包 1.二维数组(不常用 #include<iostream> ...
- 开源堡垒机GateOne的安装、配置笔记
因为内部临时需要这么一套系统,所以搜搜查查,搞定了系统部署,使用pam认证的配置. 系统初始化是使用CentOS 6.5 Mini x64版本. 首先exports http_proxy和http ...
- CSS框架分析与网站的CSS架构
框架(framework)是一个基本概念上的结构,用于去解决或者处理复杂的问题,是一种可复用的构架. 我们对CSS框架这个词比较陌生,但对于JavaScript框架就比较熟悉了,比如jQuery 但为 ...
- Spring依赖注入 --- 简单使用说明
Spring依赖注入 --- 简单使用说明 本文将对spring依赖注入的使用做简单的说明,enjoy your time! 1.使用Spring提供的依赖注入 对spring依赖注入的实现方法感兴趣 ...
- .NET中的Newtonsoft.Json.JsonConvert.SerializeObject(string a)
1.將string a 序列化為Json格式: 2.使用條件:將Newtonsoft.Json.dll作為引用添加到項目中.下载地址在这:http://json.codeplex.com/
- BITED程序员语言学习心得之:C#语言基础
一.HelloWorld 我们先来看看最简单的C#代码——HelloWorld: using System; using System.Collections.Generic; using Syste ...
- VS2012打包部署Winform程序
打包前的准备工作: 新建一个打包部署项目,点OK,如果是第一次使用的话,会打开一个网页,按照提示的步骤来做, 点击上面的step2的网址,进入到另一个网页: 填写完右边的信息,点击“download ...
- [ZZ] C++ pair
Pair类型概述 pair是一种模板类型,其中包含两个数据值,两个数据的类型可以不同,基本的定义如下: pair<int, string> a; 表示a中有两个类型,第一个元素是int型的 ...
- Tmux常用快捷键以及我会常到的一些问题汇总
今天部署测试服务器环境 使用到了tmux 刚开始我把tmux想象成了像omzsh这种shell 但是被指出是错误的,tmux类似于在shell里面的软件.我还真是第一次接触到这个概念. 首先安装 br ...
- Determining Equality of Objects
[Determining Equality of Objects] If you need to determine whether one object is the same as another ...