方法 是关联了特定类型的函数。类,结构体以及枚举都能定义实例方法,方法封装了给定类型特定的任务和功能。类,结构体和枚举同样可以定义类型方法,这是与类型本身关联的方法。类型方法与 Objective-C 中的类方法相似。
事实上在 结构体和枚举中定义方法是 Swift 语言与 C 语言和 Objective-C 的主要区别。在 Objective-C 中,类是唯一能定义方法的类型。但是在 Swift ,你可以选择无论类,结构体还是方法,它们都拥有强大的灵活性来在你创建的类型中定义方法。
实例方法
实例方法 是属于特定类实例、结构体实例或者枚举实例的函数。他们为这些实例提供功能性,要么通过提供访问和修改实例属性的方法,要么通过提供与实例目的相关的功能。实例方法与函数的语法完全相同,就如同函数章节里描述的那样。
要写一个实例方法,你需要把它放在对应类的花括号之间。实例方法默认可以访问同类下所有其他实例方法和属性。实例方法只能在类型的具体实例里被调用。它不能在独立于实例而被调用。
class Counter { var count = 0 func increment() { count += 1 } func increment(by amount: Int) { count += amount } func reset() { count = 0 } }
调用
let counter = Counter() // the initial counter value is 0 counter.increment() // the counter's value is now 1 counter.increment(by: 5) // the counter's value is now 6 counter.reset() // the counter's value is now 0
self 属性
每一个类的实例都隐含一个叫做 self的属性,它完完全全与实例本身相等。你可以使用 self属性来在当前实例当中调用它自身的方法。
在上边的例子中, increment()方法可以写成这样:
func increment() { self.count += 1 }
实际上,你不需要经常在代码中写 self。如果你没有显式地写出 self,Swift会在你于方法中使用已知属性或者方法的时候假定你是调用了当前实例中的属性或者方法。这个假定通过在 Counter的三个实例中使用 count(而不是 self.count)来做了示范。
对于这个规则的一个重要例外就是当一个实例方法的形式参数名与实例中某个属性拥有相同的名字的时候。在这种情况下,形式参数名具有优先权,并且调用属性的时候使用更加严谨的方式就很有必要了。你可以使用 self属性来区分形式参数名和属性名。
这时, self就避免了叫做 x 的方法形式参数还是同样叫做 x 的实例属性这样的歧义。
struct Point { var x = 0.0, y = 0.0 func isToTheRightOf(x: Double) -> Bool { return self.x > x } } let somePoint = Point(x: 4.0, y: 5.0) if somePoint.isToTheRightOf(x: 1.0) { print("This point is to the right of the line where x == 1.0") }
在实例方法中修改值类型
结构体和枚举是值类型 默认情况下 值类型属性不能被自身的实例方法修改。
如果你需要在特定的方法中修改结构体或者枚举的属性,你可以选择将这个方法异变。然后这个方法就可以在方法中异变(改变她的属性),并且任何改变在方法结束的时候都会写入原始的结构体中。方法同样可以指定一个全新的实例给他隐含的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(deltaX: 2.0, y: 3.0) print("The point is now at (somePoint.x) (somePoint.y)")
例子中的Point 结构体定义了一个异变方法 moveBy(x:y:),它以特定的数值移动一个 Point实例。相比于返回一个新的点,这个方法实际上修改了调用它的点。被添加到定义中的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) } }
枚举的异变方法可以设置隐含的self属性为形同枚举里的不同成员
enum TriStateSwitch { case off,low,high mutating func next() { switch self { case .off: self = .low case .low: self = .high default: self = .off } } } var ovenLight = TriStateSwitch.low ovenLight.next()//.high ovenLight.next()//.off
类型方法
与OC一样 Swift中的方法也分为实例方法和类型方法(类方法 实例不能调用 使用类本身调用) OC是使用+号声明的方法被称作类方法,但是在Swift中 可以在func前面加上关键字static来实现类方法。在类中这个关键字也可以改为class。
需要注意的是 在类方法的函数体中隐含的self属性指向了类本身而不是这个类的实例。对于结构体和枚举这意味着你可以使用self来消除类型属性和类方法形式参数之间的歧义,用法和实例属性与实例方法形式参数之间的用法完全相同。
struct LevelTracker { //类型属性 static var highestUnlokedLevel = 1 var currentLevel = 1 static func unLock(level:Int) { if level > highestUnlokedLevel { highestUnlokedLevel = level } } static func isUnlocked(level:Int) ->Bool { return level <= highestUnlokedLevel } @discardableResult mutating func advance(to level:Int) ->Bool { if LevelTracker.isUnlocked(level: level) { currentLevel = level return true }else { return false } } } class Player { var tracker = LevelTracker() let playerName:String func completedLevel(level:Int){ LevelTracker.unLock(level: level + 1) tracker.advance(to: level + 1) } init(name:String) { playerName = name } } var player1 = Player(name: "tian") player1.completedLevel(level: 1) LevelTracker.highestUnlokedLevel player1 = Player(name: "lian") if player1.tracker.advance(to: 6) { print("player is now on 6") } else { print("level 6 has not yet been unlocked") }