首页 > 代码库 > swift 笔记 (十一) —— 方法(类,结构体,枚举)

swift 笔记 (十一) —— 方法(类,结构体,枚举)

Methods (方法)

实例方法(Instance Methods)
我认为看到这里。我们唯能八一八的就是swift的自做主张的行为了,反正它就是会以各种方式帮助我们来完毕让代码看起来非常奇怪的事情。。。

在之前函数那一篇笔记中,我们已经看到过參数的外部名字和内部名字的区分了,当然。在实例方法中,这个事情依旧存在,并且。swift又会帮我们做一些潜规则。

swift在默认的情况下,会为方法的第一个參数仅仅提供函数内部使用的名字,而从第二个參数開始,既能够外部用,也能够内部用(就像我们在函数中见过的  External Parameter 一样):

class MyClass{
     var myNum: Int = 0
     func increaseNum(base: Int, numberOfTimes: Int) {
          myNum += base * numberOfTimes
     }
}

var myClassInstance = MyClass()
myClassInstance.increase(10, numberOfTime: 8)   //第二个參数開始,会自己主动的提供一个外部使用变量名 
(感谢 swift技术交流第一平台(355277)的群友 偏未晚(1027115179) 指出错这里的函数名笔误 )
myClassInstance.increaseNum(10, numberOfTime: 8)   //第二个參数開始,会自己主动的提供一个外部使用变量名

这就相当于。我们在函数那部分提到的函数想为外部提供一个变量名的话,有两种做法:
1.  func myFunc(value paramA: Int)  {……}    //value是给外部用的名字, paramA是给内部用的
2.  func myFunc(#paramA: Int) {……}     //paramA 既是外部用的,也是内部用的

而在上面的MyClass类的实例方法中。相当于,从第二个參数開始。swift自己主动为我们提供人了”#”的功能。而不须要我们明白的写#
这个默认的行为,有时候是很讨厌的,所以swift依旧提供给我们不给外部提供名字的方法:
class MyClass{
     var myNum: Int = 0
     func increaseNum(base: Int, numberOfTimes: Int) {      //注意这一行有一个 “_"
          myNum += base * numberOfTimes
     }

在參数的名字前面加了一个”_”和一个空格,这样,swift便不再会自己主动提供外部使用名字了。

当然。假设我们把”_”这里,换成别的名字,那么就跟之前说的函数是一样的了。


self 属性
每一个实例。都有一个属性用于表示它自己这个实例。这个属性叫做self。
class MyClass{
     var  num: Int = 0
     func setNum(num:Int) {
          self.num = num            //注意这里的self
     }
假设出现这个setNum方法的情况,传入的參数名叫num, 而我们设置的属性也叫num的时候,为了区分,究竟是传入的值还是实例的属性。我们为实例属性前面加了self,表示是这个实例自己的属性。


Mutating方法
以上面说的都是类的情况。那么对于 struct, enum这种值传递类型,却不能使用实例方法来改变属性的值。

struct MyPoint {
     var x = 0, y = 0
     mutating func moveByXY(deltaX: Int, y deltaY: Int) {    //注意这里的mutatingkeyword
          x += deltaX
          y += deltaY
     }
}

var instance = MyPoint()
instance.moveByXY(3, y: 4)
println(“x:\(instance.x)  y:\(instance.y)”)
在struct, enum里使用mutatingkeyword,以达到和class里一样的效果
注意:假设上面的x,和y 不是var,而是let的话,是不能用的,由于我们不能改变一个常量的值。

在Mutating方法中,给self赋值
struct MyPoint {
     var x = 0, y = 0
     mutating func changeSelf(deltaX: Int, y deltaY: Int) {
          self = MyPoint (x: deltaX, y: deltaY)      //注意这里的selfkeyword
     }

var instance = MyPoint()
instance.changeSelf(3, y: 4)
println(“x:\(instance.x)  y:\(instance.y)”)

这样的方式,也相同达到了改变 instance中的x和y的目的,然而,这样的给self赋值的方法。却是生成了一个新的MyPoint的实例(而之前的实例是怎样销毁的。内存怎样释放的。要等到后面讲到内存管理的章节才干说到,这里临时不考虑)

enum MyStateMachine {
     case None, Init, Run, Deinit
     mutating func nextState() {
          switch self {
               case None:
                    self = Init
               case Init:
                    self = Run
               case Run:
                    self = Deinit
               case Deinit:
                    self = None
          }
     }
}

var stateMachine = MyStateMachine.None
stateMachine.nextState()                                        //self变成 Init
println(stateMachine == MyStateMachine.Init)          // true

stateMachine.nextState()                                        //self 变成 Run
println(stateMachine == MyStateMachine.Init)          //true

这就非常有意思了,状态机的状态切换的代码能够直接写在enum的定义中

类型方法
上面提到的方法。都是实例相关的方法,它们都是针对某一个实例进行操作的,而类型方法,是对于这个类型的,事实上这样的方法在上一篇笔记中,类型属性的那部分已经出现过keyword了:static和class。


class MyClass {
     class var computedProperty: Int {          //这是一个类型属性,上一篇笔记中提到的

     }

     class func someMethod() {                    //这才是一个类型方法

     }
}

由于类里面的类型属性只能用于计算。不能保存数据。所以类里的类型方法,临时还不适合写一个能够跑起来的样例,应该结合struct 或者enum,才干够写,还是先看看struct的类型方法吧,enum和struct差点儿相同(这是个官方样例, 方便复制就不帖图了。不过抄了一遍。由于我非常喜欢这个样例,在实际的游戏开发中非经常常使用):

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 {               //Mutating方法,是个实例方法
          if LevelTracker.levelIsUnlocked(level) {
               currentLevel = level
               return true
          } else {
               return false
          }
     }
}

class Player {
     var tracker = LevelTracker()          //上面定义的结构体的一个实例
     let playerName: String
     func completedLevel( level: Int) {
          LevelTracker.unlockLevel(level + 1)          //调用了上面那个结构体的类型方法
          tracker.advanceToLevel(level + 1)             //调用了tracker这个实例的Mutating方法(实例方法)
     }

     init(name: String) {
          playerName = name                  //关于这个playerName常量初始化问题,在后面的章节会提到
     }
}

var player = Player(name: “World”)
player.completedLevel(1)                    //这个函数调用后 tracker的highestUnlockedLevel 会变成2

println(“highest unlocked  level is now \(LevelTracker.highestUnlockedLevel)”)

var player2 = Player(name: “Kitty”)
if player2.tracker.advanceToLevel(6) {          //检測能否够把player2设置为6级
     println(“player is now on level6")
} else {
     println(“level 6 has not yet been unlocked")
}

执行结果是else中的println被执行。
这个样例,假设上面的内容都看懂了的话,读起来应该非常easy。假设还是不懂,那么请回结合上一篇笔记一起看。

swift 笔记 (十一) —— 方法(类,结构体,枚举)