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了。

后记

未完,待续~~~

swift简单总结(二十一)—— 方法_第1张图片
风景

你可能感兴趣的:(swift简单总结(二十一)—— 方法)