摘要:类、结构体、枚举都可以定义实例方法;实例方法为给定类型的实例封装 了具体的任务与功能。类、结构体、枚举也可以定义类型方法;类型方法与类型本身相关联。类型方法与 Objecti ve-C 中的类方法(class methods)相似。
结构体和枚举能够定义方法是 Swift 与 C/Objective-C 的主要区别之一。在 Objective-C 中,类是唯一能定义 方法的类型。但在 Swift 中,你不仅能选择是否要定义一个类/结构体/枚举,还能灵活的在你创建的类型(类/结 构体/枚举)上定义方法。
实例方法
实例方法是属于某个特定类、结构体或者枚举类型实例的方法。具体说明略
方法的局部参数名称和外部参数名称
Swift 中方法的名称通常用一个 介词指向方法的第一个参数,比如:  with,for,by  等等。也就是说能通过方法名直接明白第一个参数的含义,所以Swift 默认仅给方法的第一个参数名称一个局部参数名称;默认同时给第二个和后续的参数名称局部参 数名称和外部参数名称。
例func incrementBy(amount: Int,numberOfTimes: Int),两个参数amount和numberOfTimes,默认情况下,Swift 只把amoun当作一个局部名称numberOfTimes看作局部名称又看作外部名称,方法名: incrementBy(_numberOfTimes:)已经能很清楚地 看出它的作用
修改方法的外部参数名称
有时为方法的第一个参数提供一个外部参数名称是非常有用的,尽管这不是默认的行为。你可以自己添加一个显 式的外部名称或者用一个井号( # )作为第一个参数的前缀来把这个局部名称当作外部名称使用。
在实例方法中修改值类型
结构体和枚举是值类型。一般情况下,值类型的属性不能在它的实例方法中被修改。
但是,如果你确实需要在某个具体的方法中修改结构体或者枚举的属性,你可以选择 变异(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)"
上面的 Point 结构体定义了一个变异方法(mutating method) moveByX(_:y:) 用来移动点。 moveByX 方法 在被调用时修改了这个点,而不是返回一个新的点。方法定义时加上 mutating 关键字,这才让方法可以修改值 类型的属性。
注意:不能在结构体类型常量上调用变异方法,因为常量的属性不能被改变
在变异方法中给self赋值
变异方法能够赋给隐含属性 self 一个全新的实例。上面 Point 的例子可以用下面的方式改写:
struct Point {
var x = 0.0,y deltaY: Double) {
self = Point(x: x + deltaX,y: y + deltaY) }
}
类型方法(类方法)
定义类型本身调用的方法,这种方法就叫做类型方法。声明 结构体和枚举的类型方法,在方法的 func 关键字之前加上关键字 static 。类可能会用关键字 Class 来允许子类 重写父类的实现方法。
注意:在 Objective-C 里面,你只能为 Objective-C 的类定义类型方法(type-level methods)。在 Swift 中,你 可以为所有的类、结构体和枚举定义类型方法:每一个类型方法都被它所支持的类型显式包含。
例:
类的类型方法:
class SomeClass {
class func someTypeMethod() {
// type method implementation goes here }
} SomeClass.someTypeMethod()
下面是一个很有趣的例子,它定义了一个名为 LevelTracker 结构体。它监测玩家的游戏发展情况(游戏的不同层次或阶段)。这 是一个单人游戏,但也可以存储多个玩家在同一设备上的游戏信息。
游戏初始时,所有的游戏等级(除了等级 1)都被锁定。每次有玩家完成一个等级,这个等级就对这个设备上的所 有玩家解锁。 LevelTracker 结构体用静态属性和方法监测游戏的哪个等级已经被解锁。它还监测每个玩家的当 前等级。
struct LevelTracker {
static var highestUnlockedLevel = 1 static func unlockLevel(level: Int) {
if level > highestUnlockedLevel { highestUnlockedLevel = level } }
static func levelIsUnlocked(level: Int) -> Bool { return level <= highestUnlockedLevel
}
var currentLevel = 1
mutating func advanceToLevel(level: Int) -> Bool {
if LevelTracker.levelIsUnlocked(level) { currentLevel = level
return true
} else {
return false
} }
}
尽管我们没有使用类似 LevelTracker.highestUnlockedLeve l 的写法,这个类型方法还是能够访问静态属性 highestUnlockedLevel )
下面,Player 类使用 LevelTracker 来监测和更新每个玩家的发展进度:
class Player { var tracker = LevelTracker() let playerName: String func completedLevel(level: Int) { LevelTracker.unlockLevel(level + 1) tracker.advanceToLevel(level + 1) } init(name: String) { playerName = name } }
下标脚本
下标脚本 可以定义在类(Class)、结构体(structure)和枚举(enumeration)这些目标中,可以认为是访问 集合(collection),列表(list)或序列(sequence的快捷方式,使用下标脚本的索引设置和获取值,不需要 再调用实例的特定的赋值和访问方法。
与定义实例方法类似,定义下标脚本使用 subscript 关键字,显式声明入参(一个 或多个)和返回类型。与实例方法不同的是下标脚本可以设定为读写或只读。这种方式又有点像计算型属性的get ter和setter:例
subscript(index: Int) -> Int {
get {
// 返回与入参匹配的Int类型的值 }
set(newValue) {
// 执行赋值操作
}
}
与只读计算型属性一样,可以直接将原本应该写在 get 代码块中的代码写在 subscript 中:
subscript(index: Int) -> Int {
// 返回与入参匹配的Int类型的值
}
下面代码演示了一个在 TimesTable 结构体中使用只读下标脚本的用法,该结构体用来展示传入整数的n倍。
struct TimesTable {
let multiplier: Int subscript(index: Int) -> Int {
return multiplier * index }
}
let threeTimesTable = TimesTable(multiplier: 3)
print("3的6倍是\(threeTimesTable[6])")
// 输出 "3的6倍是18"
var numberOfLegs = ["spider": 8,"ant": 6,"cat": 4]
numberOfLegs["bird"] = 2
//在字典中添加了一个key为bird,值为2的数据
初学笔记,不喜勿喷,欢迎指点!