swift简单总结(二十一)—— 方法

版本记录

版本号 时间
V1.0 2017.07.29

前言

我是swift2.0的时候开始接触的,记得那时候还不是很稳定,公司的项目也都是用oc做的,并不对swift很重视,我自己学了一段时间,到现在swift3.0+已经出来了,自己平时也不写,忘记的也差不多了,正好项目这段时间已经上线了,不是很忙,我就可以每天总结一点了,希望对自己对大家有所帮助。在总结的时候我会对比oc进行说明,有代码的我会给出相关比对代码。
1. swift简单总结(一)—— 数据简单值和类型转换
2. swift简单总结(二)—— 简单值和控制流
3. swift简单总结(三)—— 循环控制和函数
4. swift简单总结(四)—— 函数和类
5. swift简单总结(五)—— 枚举和结构体
6. swift简单总结(六)—— 协议扩展与泛型
7. swift简单总结(七)—— 数据类型
8. swift简单总结(八)—— 别名、布尔值与元组
9. swift简单总结(九)—— 可选值和断言
10. swift简单总结(十)—— 运算符
11. swift简单总结(十一)—— 字符串和字符
12. swift简单总结(十二)—— 集合类型之数组
13. swift简单总结(十三)—— 集合类型之字典
14. swift简单总结(十四)—— 控制流
15. swift简单总结(十五)—— 控制转移语句
16. swift简单总结(十六)—— 函数
17. swift简单总结(十七)—— 闭包(Closures)
18. swift简单总结(十八)—— 枚举
19. swift简单总结(十九)—— 类和结构体
20. swift简单总结(二十)—— 属性

方法

  大家还记得OC中的方法吧,包括对象方法和类方法。在swift中同样有方法,方法是某些特定类型相关联的函数。类、结构体和枚举都可以定义实例方法,实例方法为给定类型的实例封装了具体的任务和功能。类、结构体和枚举也可以定义类型方法,类型方法与类型相关联,与OC中的类方法相似。

  结构体和枚举能定义方法是swiftOC的主要区别,在OC中,类是唯一能够定义方法的类型,但是在swift中,你可以选择是否定义一个类、结构体还是枚举,还能灵活的在你定义的类、结构体、枚举中定义方法。

本篇文章主要从下面进行讲述:

  • 实例方法(Instance Methods)
  • self 属性
  • 类型方法(Type Methods)

实例方法

  实例方法属于某一个特定的类、结构体或者枚举类型实例方法,实例方法提供访问和修改实例属性的方法或提供与实例目的相关的功能,并以此支撑实例的功能,实例方法的语法与函数完全一致。

  实例方法要写在它所属的类型前后大括号之间,实例方法能够隐式访问它所属类型的所有其他实例方法和属性,实例方法只能被它所属的类的某个特定实例调用,实例方法不能脱离于现存的实例而被调用。

下面看一个例子。

class JJSwiftVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        let counter = Counter()
        counter.increment()
        counter.incrementBy(step: 10)
        counter.rest()
    }
}

class Counter {
    var count = 0
    func increment() {
        count += 1
        print(count)
    }
    
    func incrementBy(step : Int) {
        count += step
        print(count)
    }
    
    func  rest() {
        count = 0
        print(count)
    }
}

下面看输出结果

1
11
0

这里类Counter定义了三个方法func increment()func incrementBy(step : Int)func rest()

1. 方法的局部参数名称和外部参数名称 - Local and External Parameter Names for Methods

  讲解函数的时候,我们知道函数可以同时有一个局部名称(在函数体内部使用)和一个外部名称(在调用函数时使用)。方法参数也是一样的,但是方法和函数的局部名称和外部名称的默认行为是不一样的。

  方法参数列表与OC很类似,你不必定义成外部参数,swift会默认方法的参数为外部参数,下面看一下例子。

class JJSwiftVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        let counter = Counter()
        counter.incrementBy(amount: 10, numberOfTimes: 5)
    }
}

class Counter {
    var count : Int = 0
    func incrementBy(amount : Int, numberOfTimes : Int) {
        count += amount * numberOfTimes
        print(count)
    }
}

下面看输出结果

50

这里,大家注意下:

counter.incrementBy(amount: 10, numberOfTimes: 5)

调用的时候都默认两个参数都有外部参数了。


self 属性

  类型的每一个实例都有一个隐含属性叫做selfself完全等同于该实例本身,你可以在一个实例的实例方法中使用这个隐含的self属性来引用当前实例。

上面的例子可以改写为:

class Counter {
    var count : Int = 0
    func incrementBy(amount : Int, numberOfTimes : Int) {
        self.count += amount * numberOfTimes
        print(count)
    }
}

可见,增加了self也是可以的。

self.count += amount * numberOfTimes

这里,self不是必须的,swift假定你是指当前实例的属性或者方法。但是有的时候self有它好用的地方。

struct Point {
    var x = 0.0
    var y = 0.0
    func isToTheRightOfX(x : Double) -> Bool {
        print(self.x)
        print(x)
        return self.x > x
    }
}

class JJSwiftVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        let somePoint = Point(x: 4.0, y: 5.0)
        if somePoint.isToTheRightOfX(x: 1.0) {
            print("This point is to the right of the line where x == 1.0")
        }
    }
}

下面看输出结果

4.0
1.0
This point is to the right of the line where x == 1.0

  这种情况使用self就有用了,如果不使用selfswift就认为两次使用的x都是指的是名称为x的函数参数。但是这个情况完全可以避免,我们可以定义函数参数的时候不与结构体成员变量重复,容易引起歧义,代码的可读性也会差很多。

1. 在实例方法中修改值类型 - Modifying Values Types from Within Instance Methods

  结构体和枚举都是值类型,值类型的属性不能再它的实例方法中修改。但是,如果你确实需要在某个具体方法中修改结构体或者枚举的属性,你可以选择使用变异mutating这个方法,然后方法就可以从方法内部改变它的属性,并且它做的任何改变在方法结束时还保留在原始结构中。方法还可以给它隐含self属性赋值一个全新的实例,这个新实例在方法结束后将替换原来的实例。

下面看代码。

struct Point {
    var x = 0.0
    var y = 0.0
    mutating func movePoint(deltaX : Double, deltaY : Double) {
        x += deltaX
        y += deltaY
        print("(\(x),\(y))")
    }
}

class JJSwiftVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        var somePoint = Point(x : 1.0, y : 2.0)
        somePoint.movePoint(deltaX: 5.0, deltaY: 5.0)
    }
}

下面看输出结果

(6.0,7.0)

还有一点,下面的必须定义为变量var,才可以修改。

var somePoint = Point(x : 1.0, y : 2.0)

如果修改成let就会报错,即使想改变常量的变量属性也不可以。

2. 在变异方法中给self赋值 - Assigning to self within a Mutating Method

变异方法能够给隐含属性self一个全新的实例,下面看代码。

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

上面是结构体,其实对于枚举类型一样,变异方法可以把self设置为相同枚举类型中的不同成员。

下面看一下代码。

enum TriStateSwitch {
    case Off, Low, High
    
    mutating func next(){
        switch self {
        case .Off:
            self = .Low
        case .Low:
            self = .High
        case .High:
            self = .Off
        }
    }
}

class JJSwiftVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        var light = TriStateSwitch.Low
        print(light)
        
        light.next()
        print(light)
        
        light.next()
        print(light)
    }
}

下面看一下输出结果

Low
High
Off

类型方法

  它相当于OC中的类方法,在swift中叫做类型方法。声明类的类型方法是要在func关键字之前加上关键字class,声明结构体和枚举的类型方法,在方法的func关键字之前加上关键字static。也即是说你可以在swift中不仅为类定义类型方法,还可以为结构体和枚举定义类型方法。

类型方法都是按照如下方式进行调用。

class SomeClass{
  class func someTypeMethod(){
        //type method implementation goes here
   }
}

someClass.someTypeMethod()

  一个类型方法可以调用本类中另外一个类型方法的名称,而无需在方法名称前面加上类型名称的前缀,同样结构体和枚举的类型方法也能够直接通过静态属性的名称访问静态属性,而不需要类型名称前缀。

struct LevelTracker {
    static var highestUnlockLevel = 1
    static func unlockLevel(level : Int){
        if level > highestUnlockLevel {
            highestUnlockLevel = level
        }
    }
    
    static func levelIsUnlocked(level : Int) -> Bool{
        return level <= highestUnlockLevel
    }
    
    var currentLevel = 1
    mutating func advanceToLevel(level : Int) -> Bool {
        if LevelTracker.levelIsUnlocked(level: level){
            currentLevel = level
            return true
        }
        else {
            return false
        }
    }
}

LevelTracker监测玩家已解锁的最高等级,这个值被存储在静态属性highestUnlockLevel中,LevelTracker还定义了两个类型方法unlockLevellevelIsUnlocked,方法unlockLevel:一旦新等级被解锁,就会更新highestUnlockLevel的值,方法levelIsUnlocked:如果某个给定的等级已经解锁就会返回true。同时,currentLevel用于监测玩家当前等级,定义了advanceToLevel实例方法进行管理,这个方法会在更新currentLevel之前判断请求的等级是否已经解锁,返回的是一个Bool值。

下面我们看玩家类使用LevelTracker监测和更新每一个玩家的发展进度。

class Player {
    var tracker = LevelTracker()
    let playerName : String
    
    func completedLevel(level : Int) {
        LevelTracker.unlockLevel(level: level + 1)
        tracker.advanceToLevel(level: level + 1)
    }
    
    init(name: String) {
        playerName = name
    }
}

Player类创建了一个LevelTracker实例tracker来监测这个用户的等级进度,提供了方法completedLevel:一旦玩家完成某个指定等级就调用它,这个方法为所有玩家解锁下一级,并更新当前进度为下一等级。

下面我们看全部完整代码。

struct LevelTracker {
    static var highestUnlockLevel = 1
    static func unlockLevel(level : Int){
        if level > highestUnlockLevel {
            highestUnlockLevel = level
        }
    }
    
    static func levelIsUnlocked(level : Int) -> Bool{
        return level <= highestUnlockLevel
    }
    
    var currentLevel = 1
    mutating func advanceToLevel(level : Int) -> Bool {
        if LevelTracker.levelIsUnlocked(level: level){
            currentLevel = level
            return true
        }
        else {
            return false
        }
    }
}

class JJSwiftVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        var player = Player(name : "John")
        player.completedLevel(level: 1)
        print("highest level is unlocked is \(LevelTracker.highestUnlockLevel)")
    }
}

class Player {
    var tracker = LevelTracker()
    let playerName : String
    
    func completedLevel(level : Int) {
        LevelTracker.unlockLevel(level: level + 1)
        tracker.advanceToLevel(level: level + 1)
    }
    
    init(name: String) {
        playerName = name
    }
}

下面看输出结果

highest level is unlocked is 2

现在可以看见未解锁的等级到了2了。

后记

未完,待续~~~

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

推荐阅读更多精彩内容