方法

类、结构体、枚举都可以定义实例方法,实例方法为给定类型实例封装了具体的任务和功能

类、结构体、枚举也可定义类型方法,类型方法与类型本身关联(与OC中类似)

实例方法

实例方法提供访问和修改实例属性的方法或提供与实例目的相关的功能,并以此来支撑实例的功能。
实例方法的语法与函数完全一致

实例方法能够隐式访问它所属类型的所有的其他实例方法和属性

class Counter {
    var count = 0
    func increment() {
        count += 1
    }
    func increment(by amount: Int) {
        count += amount
    }
    func reset() {
        count = 0
    }
}

let counter = Counter()
// 初始计数值是0
counter.increment()
// 计数值现在是1
counter.increment(by: 5)
// 计数值现在是6
counter.reset()
// 计数值现在是0

self属性

与OC类似,self等同于该类型的实例本身

//所以我们可以这么写
func increment() {
    self.count += 1
}

其实没必要写self,使用已知的属性名或者方法名 swift会假定你使用的是当前实例属性或者方法

我们使用的主要场景:
实例方法的某个参数名称与实例的某个属性名称相同的时候,此时优先使用参数名,因此我们通过self属性来进行区分使用属性

struct Point {
    var x = 0.0, y = 0.0
    func isToTheRightOfX(_ x: Double) -> Bool {
        return self.x > x//用self来区分属性
    }
}

let somePoint = Point(x: 4.0, y: 5.0)

if somePoint.isToTheRightOfX(1.0) {
    print("This point is to the right of the line where x == 1.0")
}
// 打印 "This point is to the right of the line where x == 1.0"

实例方法中修改值类型

结构体和枚举是值类型。默认情况下,值类型的属性不能在它的实例方法中被修改

我们可以通过给这个实例方法选择可变(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赋值

可以在可变方法中给隐含属性self赋予一个新的实例

struct Point1 {
    var x = 0.0, y = 0.0
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        self = Point1(x: x + deltaX, y: y + deltaY)
    }
}

创建一个新的结构体实例赋值给self,替换现在的实例

枚举的可变方法,定义了一个三态开关状态枚举,通过调用next()进行切换状态

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 CustomClass{
    class func method1() {
        print("父方法")
    }
}

class CustomSubClass: CustomClass{
    //子类重写父类静态方法
    override class func method1() {
        print("子方法")
    }
}

注意:

oc中只能为类定义类型方法
swift中可以为类,结构体,枚举定义类方法

类型方法在类型上通过点语法调用
在类型方法中,self指向类型本身,同样的可以用其来区分同样的类型属性和类型方法参数

在类型方法体中可以调用本类中类型属性或的其他类型方法,调用是可以直接通过类型方法名称或者类型属性名称进行调用,而不用在前面添加类型名称

//检测玩家等级的结构体
struct LevelTracker {
    static var highestUnlockedLevel = 1
    var currentLevel = 1
    static func unlock(_ level: Int) {
        if level > highestUnlockedLevel { highestUnlockedLevel = level }
    }
    static func isUnlocked(_ level: Int) -> Bool {
        return level <= highestUnlockedLevel
    }
    //因为允许在调用 advance(to:) 时候忽略返回值,不会产生编译警告,所以函数被标注为 @discardableResult 属性
    @discardableResult 
    mutating func advance(to level: Int) -> Bool {
        if LevelTracker.isUnlocked(level) {
            currentLevel = level
            return true
        } else {
            return false
        }
    }
}
//玩家类
class Player {
    var tracker = LevelTracker()
    let playerName: String
    func complete(level: Int) {
        LevelTracker.unlock(level + 1)
        tracker.advance(to: level + 1)
    }
    init(name: String) {
        playerName = name
    }
}
var player = Player(name: "Argyrios")
player.complete(level: 1)
print("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")
// 打印 "highest unlocked level is now 2"

player = Player(name: "Beto")
if player.tracker.advance(to: 6) {
print("player is now on level 6")
} else {
print("level 6 has not yet been unlocked")
}
// 打印 "level 6 has not yet been unlocked"