Swift复习系列:方法

Swift语言中,方法分两种:

  • 实例方法,为给定类型的实例封装 了具体的任务与功能,通过实例对象来调用;
  • 类型方法,和类型本身相关联,通过类型名称来调用。

方法(Method)使用适用于类、结构体和枚举。

结构体和枚举能够定义方法是SwiftC/Objective-C的主要区别之一。在Objective-C中,类是唯一能定义 方法的类型。但在Swift中,你不仅能选择是否要定义一个类/结构体/枚举,还能灵活地在你创建的类型(类/ 结构体/枚举)上定义方法。

实例方法(Instance Methods)

    1. 实例方法是属于某个特定类、结构体或者枚举类型实例的方法。实例方法提供访问和修改实例属性的方法或提供
      与实例目的相关的功能,并以此来支撑实例的功能。
    1. 实例方法要写在它所属的类型的前后大括号之间。实例方法能够隐式访问它所属类型的所有的其他实例方法和属
      性。实例方法只能被它所属的类的某个特定实例调用。实例方法不能脱离于现存的实例而被调用。

如下例子

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属性

类型的每一个实例都有一个隐含属性叫做selfself 完全等同于该实例本身。你可以在一个实例的实例方法中 使用这个隐含的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)

    1. 类型方法是定义在类型本身上调用的方法,这一点和Objective-C中的静态方法类似,都是通过类型名来调用该方法。
    1. 在方法的func 关键字之前加上关键字static,来指定类型方法。类还可以用关键字class来允许子类重写 父类的方法实现
    1. 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
    1. 在类型方法的方法体(body)中,self指向这个类型本身,而不是该类型的某个实例。这意味着我们可以用self来消除类型属性和类型方法参数之间的歧义,类似于上面处理实例属性和实例方法参数时的做法。
    1. 一般来说,在类型方法的方法体中,任何未被限定的方法和属性名称,可以被本类中的其它类型方法和类型属性引用;一个类型方法可以通过类型方法名称直接调用本类中的其它类型方法,不用直接通过类型名来调用;在结构体和枚举中,也能够直接通过类型属性的名称访问本类中的类型属性,而不需要前面加上类型名称。

请看下面的例子

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对象设置一个还未被解锁的等级时,就会提示解锁失败。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容