方法是与特定类型关联的函数。类,结构和枚举都可以定义实例方法,这些实例方法封装了用于处理给定类型的实例的特定任务和功能。类,结构和枚举也可以定义与类型本身相关联的类型方法。类型方法类似于Objective-C中的类方法。
结构和枚举可以在Swift中定义方法这一事实与C和Objective-C的主要不同之处。在Objective-C中,类是唯一可以定义方法的类型。在Swift中,您可以选择是定义类,结构还是枚举,并且仍然可以灵活地在创建的类型上定义方法。
实例方法
实例方法是属于特定类,结构或枚举的实例的函数。它们通过提供访问和修改实例属性的方式,或者通过提供与实例目的相关的功能,来支持那些实例的功能。实例方法具有与函数完全相同的语法。
您可以在实例方法的所属类型的大括号内编写一个实例方法。实例方法可以隐式访问该类型的所有其他实例方法和属性。实例方法只能在其所属类型的特定实例上调用。没有现有实例就不能孤立地调用它。
self属性
类型的每个实例都有一个称为的隐式属性self,它与实例本身完全等效。您可以使用该self属性在其自己的实例方法中引用当前实例。
实际上,您不需要self经常编写代码。如果您未明确编写self,则Swift会假设您在方法中使用已知的属性或方法名称时,都在引用当前实例的属性或方法。当实例方法的参数名称与该实例的属性名称相同时,参数名称优先,因此有必要以更限定的方式引用该属性。您可以使用self属性来区分参数名称和属性名称。
从实例方法中修改值类型
结构和枚举是值类型。默认情况下,不能从其实例方法中修改值类型的属性。
但是,如果你需要一个特定的方法修改您的结构或枚举的属性,你可以选择mutating修饰该方法。然后,该方法可以从方法内部更改(即更改)其属性,并在方法结束时将其所做的任何更改写回到原始结构。该方法还可以为其隐式self属性分配一个全新的实例,并且该新实例将在方法结束时替换现有实例。
struct Point {
var x=0.0,y=0.0
mutating func moveBy(x deltaX:Double, y deltaY:Double) {
x+=deltaX
y+=deltaY
}
}
var somePoint=Point(x:1.0, y:1.0)
somePoint.moveBy(x:2.0, y:3.0)
print("The point is now at (\(somePoint.x),\(somePoint.y))")
// Prints "The point is now at (3.0, 4.0)"
Point上面的结构定义了一种变异moveBy(x:y:)方法,该方法将Point实例移动一定量。实际上,此方法不会返回新点,而是会修改其调用点。将mutating关键字添加到其定义中,以使其能够修改其属性。
请注意,您不能在结构体类型的常量上调用mutating方法,因为它的属性即使是可变属性也无法更改。
类型方法
实例方法是您在特定类型的实例上调用的方法。您还可以定义在类型本身上调用的方法。这些方法称为类型方法。您可以通过static在方法的func关键字之前编写关键字来指示类型方法。类可以改用class关键字,以允许子类覆盖该方法的超类实现。
在Objective-C中,您只能为Objective-C类定义类型级别的方法。在Swift中,您可以为所有类,结构和枚举定义类型级别的方法。每个类型方法都明确地限定于它支持的类型。类型方法使用点语法来调用,就像实例方法一样。但是,您在类型上而不是在该类型的实例上调用类型方法。
在类型方法的主体内,隐式self属性引用类型本身,而不是该类型的实例。这意味着您可以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
}
@discardableResult
mutating func advance(to level:Int) ->Bool{
if LevelTracker.isUnlocked(level) {
currentLevel= level
returntrue
}else{
returnfalse
}
}
}