在Swift
语言中,方法分两种:
- 实例方法,为给定类型的实例封装 了具体的任务与功能,通过实例对象来调用;
- 类型方法,和类型本身相关联,通过类型名称来调用。
方法(Method
)使用适用于类、结构体和枚举。
结构体和枚举能够定义方法是
Swift
与C/Objective-C
的主要区别之一。在Objective-C
中,类是唯一能定义 方法的类型。但在Swift
中,你不仅能选择是否要定义一个类/结构体/枚举,还能灵活地在你创建的类型(类/ 结构体/枚举)上定义方法。
实例方法(Instance Methods
)
- 实例方法是属于某个特定类、结构体或者枚举类型实例的方法。实例方法提供访问和修改实例属性的方法或提供
与实例目的相关的功能,并以此来支撑实例的功能。
- 实例方法是属于某个特定类、结构体或者枚举类型实例的方法。实例方法提供访问和修改实例属性的方法或提供
- 实例方法要写在它所属的类型的前后大括号之间。实例方法能够隐式访问它所属类型的所有的其他实例方法和属
性。实例方法只能被它所属的类的某个特定实例调用。实例方法不能脱离于现存的实例而被调用。
- 实例方法要写在它所属的类型的前后大括号之间。实例方法能够隐式访问它所属类型的所有的其他实例方法和属
如下例子
class StepCounter
{
var stepCount = 0
func increasement()
{
stepCount += 1
}
func increasemen(by amount:Int)
{
stepCount += amount;
}
func resetCount()
{
stepCount = 0
}
}
let counter = StepCounter.init()
for _ in 1...10
{
counter.increasement()
}
print("-01-stepCounter = \(counter.stepCount)")
counter.increasemen(by: 100)
print("-02-stepCounter = \(counter.stepCount)")
counter.resetCount()
print("-03-stepCounter = \(counter.stepCount)")
输出结果
-01-stepCounter = 10
-02-stepCounter = 110
-03-stepCounter = 0
Program ended with exit code: 0
如上,和属性一样,我们可以使用.
语法(dot syntax
)来调用实例方法。
1. self属性
类型的每一个实例都有一个隐含属性叫做self
, self
完全等同于该实例本身。你可以在一个实例的实例方法中 使用这个隐含的self
属性来引用当前实例.如下,increasement()
还可以这样写,
func increasement()
{
self.stepCount += 1
}
在项目我们不必经常写self.
,不过当参数名和属性名称一样的情况下,参数名称享有优先权,并且在引用属性时必须使用一种更严格的方式。这时你可以使用self
属性来区分参数名称和属性名称。
如下
func increasemen(by stepCount:Int)
{
self.stepCount += stepCount;
}
2. 在实例方法中修改值类型
结构体和枚举是值类型。默认情况下,值类型的属性不能在它的实例方法中被修改。但是,如果我们需要在某个特定的方法中修改结构体或者枚举的属性,可以为这个方法设置可变(mutating
) 行为,然后就可以从其方法内部改变它的属性,并且这个方法做的任何改变都会在方法执行结束时写回到原始结构中。方法还可以给它隐含的self
属性赋予一个全新的实例,这个新实例在方法结束时会替换现存实例。
如下例子
struct MyPoint
{
var x = 0.0
var y = 0.0
mutating func moveByX(typeX:Double,typeY:Double)
{
self.x += typeX
self.y += typeY
}
}
var point = MyPoint.init(x: 10, y: 10)
print("MyPoint = \(point.x,point.y)")
point.moveByX(typeX: 11, typeY: 11)
print("Now,MyPoint = \(point.x,point.y)")
运行结果
MyPoint = (10.0, 10.0)
Now,MyPoint = (21.0, 21.0)
Program ended with exit code: 00
注意:不能在结构体类型的常量(a constant of structure type
)上调用可变方法,因为其属性不能被改变,即使属性是变量属性.eg.let point02 = MyPoint.init(x: 10, y: 10)
,point02
就不能修改其属性的值。
3. 在可变方法中给Self
赋值
可变方法能够赋给隐含属性 self
一个全新的实例,上面MyPoint
的例子还可以如下写
struct MyPoint
{
var x = 0.0
var y = 0.0
mutating func moveByX(typeX:Double,typeY:Double)
{
self = MyPoint.init(x: self.x + typeX, y: self.y + typeY)
}
}
var point = MyPoint.init(x: 10, y: 10)
print("MyPoint = \(point.x,point.y)")
point.moveByX(typeX: 11, typeY: 11)
print("Now,MyPoint = \(point.x,point.y)")
在枚举的可变方法中,我们可以把self
设置为同一枚举类型的不同成员,如下
enum SwitchType
{
case Off,Low,High
mutating func nextType()
{
switch self
{
case .Off:
self = .Low
case .Low:
self = .High
case .High:
self = .Off
}
}
}
var lightingSwitchType = SwitchType.Off
lightingSwitchType.nextType()
print(lightingSwitchType)
lightingSwitchType.nextType()
print(lightingSwitchType)
运行结果:
Low
High
Program ended with exit code: 0
类型方法(Type Methods
)
- 类型方法是定义在类型本身上调用的方法,这一点和
Objective-C
中的静态方法类似,都是通过类型名来调用该方法。
- 类型方法是定义在类型本身上调用的方法,这一点和
-
在方法的
func
关键字之前加上关键字static
,来指定类型方法。类还可以用关键字class
来允许子类重写 父类的方法实现。
-
在方法的
- 在
Objective-C
中,你只能为Objective-C
的类类型(classes
)定义类型方法(type-level methods
)。在Swift
中,你可以为所有的类、结构体和枚举定义类型方法。每一个类型方法都被它所支持的类型显式包含。
- 在
如下例子
class MyTestClass
{
class func testTypeClassFunc()
{
print("这是一个类型方法!")
}
static func testSubSuperClassFunc()
{
print("这是一个类型方法,子类重写父类方法!")
}
}
MyTestClass.testTypeClassFunc()
MyTestClass.testSubSuperClassFunc()
运行结果
这是一个类型方法!
这是一个类型方法,子类重写父类方法!
Program ended with exit code: 0
- 在类型方法的方法体(
body
)中,self
指向这个类型本身,而不是该类型的某个实例。这意味着我们可以用self
来消除类型属性和类型方法参数之间的歧义,类似于上面处理实例属性和实例方法参数时的做法。
- 在类型方法的方法体(
- 一般来说,在类型方法的方法体中,任何未被限定的方法和属性名称,可以被本类中的其它类型方法和类型属性引用;一个类型方法可以通过类型方法名称直接调用本类中的其它类型方法,不用直接通过类型名来调用;在结构体和枚举中,也能够直接通过类型属性的名称访问本类中的类型属性,而不需要前面加上类型名称。
请看下面的例子
struct LevelTracker
{
static var highestUnLockLevel = 1//检测玩家已经解锁的最高等级(类型属性)
var currentLevel = 1//检测每个玩家当前的等级
static func unlock(_ level:Int)//一旦新等级被解锁,该函数就会更新highestUnLockLevel的值
{
if level > highestUnLockLevel
{
highestUnLockLevel = level
}
}
/*
*如果给定Level值<=highestUnLockLevel,说明该等级已经被解锁,就会返回true
*/
static func isUnlocked(_ level:Int) -> Bool
{
return level <= highestUnLockLevel
//也可以用下面的样式来写
//return level <= highestUnLockLevel ?true:false
}
/*
*函数被标注为 @ discardableResult,允许在调用函数时候忽略返回值
*更新currentLevel之前,判断等级是否已经解锁,如果解锁就能设置currentLevel
*/
@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
/*complete(level:)
*一旦玩家完成某个指定等级就会调用它
*并且为当前所有玩家解锁下一等级,将当前玩家的等级更新为下一级
*/
func complete(level:Int)
{
LevelTracker.unlock(level + 1)
tracker.advance(to: level + 1)
}
init(name:String)
{
playerName = name
}
}
var player = Player.init(name: "TestDemo")
player.complete(level: 1)
print("当前最高等级为:\(LevelTracker.highestUnLockLevel)")
var player2 = Player.init(name: "Hahaha")
if player2.tracker.advance(to: 8)
{
print("等级解锁成功,玩家当前等级为:\(LevelTracker.highestUnLockLevel)")
}
else
{
print("等级解锁失败")
}
运行结果
当前最高等级为:2
等级解锁失败
Program ended with exit code: 0
在上面的例子中,
LevelTracker
是游戏玩家的等级模型,highestUnLockLevel
为当前游戏所有玩家中已经解锁的最高等级,currentLevel
为每个玩家的当前等级;- 一旦新等级被解锁,就会通过
unlock(_ level:Int)
方法来更新highestUnLockLevel
的值;同时会通过isUnlocked(_ level:Int)
方法来判断一个给定的等级是否已经被解锁;advance
方法的作用请参考注释。Player
类为一个游戏玩家模型。当我们试图给player2
对象设置一个还未被解锁的等级时,就会提示解锁失败。