Swift-方法(Methods)

Posted 人散风中

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift-方法(Methods)相关的知识,希望对你有一定的参考价值。

前言

方法即是函数。结构体和枚举能够定义方法是Swift与C/Object-C的主要区别之一。在OC中,类是唯一可以定义方法的类型,而Swift中,结构体、类、枚举内部都可以定义方法。这就牵扯到夲小节所包含的两个知识点:

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

简而言之,实例方法就是我们正常建立的方法,func 关键字修饰,调用的时候先给 结构体/类/枚举 建立一个实例方法,然后使用点语法调用实例方法。而类型方法和OC中的类方法是很相似的(OC中 符号 + 开头的方法都是类方法,通常单例方法都会使用类方法,文章最下面有示例),调用的时候不用实例化 结构体/类/枚举 ,直接用他们的名字点语法类型方法名,两行代码简单直接:

struct SomeStructure 
    var name = "Tom"
    var age = 12
    //  实例方法,打印信息
    func printInfo() 
        print(name,age)
    
    //  类型方法,至于为啥用static,下面介绍
    static func counterSomeThing() 
        print("------类型方法")
    


//  调用类型方法,直接结构体名字即可
SomeStructure.counterSomeThing()
//  调用实例方法,先创建一个结构体的实例方法
let instanceMethod = SomeStructure()
//  使用点语法调用
instanceMethod.printInfo()

分条详述

  1. 实例方法
    其实通过前言中的代码段,已经很明确的说明什么是实例方法了,这里只要说一下实例方法的一些特性和注意点。

    实例方法要卸载它所属类型的大括号内,并且只能被它所属类型的某个实例方法调用,如上面实例代码,必须先建立所属类型的实例方法才能调用类型内部的实例方法。示例代码中对一个数字进行处理,管中窥豹,简单再体验下实例方法:

    class HandleDigit 
    var dight = 0
     //  自增
    func increase() 
       dight += 1
    
    //  加上某个数
    func addDight(addNumber number: Int) 
        dight += number
    
    //  重置
    func resetDight() 
        dight = 0
    
    
    var hander = HandleDigit()
    //  调用实例方法
    hander.increase()     //  digit = 1
    hander.addDight(addNumber: 100)       //  digit = 101
    hander.resetDight()     //  digit = 0

    关于方法的局部名称和外部参数名称,在前面学习的 函数小节的 函数参数名称 中有详细的介绍,包括默认第一个参数名称省略、自定义参数的描述等。其实方法、函数的本就是一个概念,如果对于书写方法有比较好的体会,那么在日常的编码中也会使自己的代码更具可读性。

    关于self属性,这个也是Swift和OC的主要区别之一。类型的每一个实例都有一个隐含的属性叫做self,self完全等同于该实例本身。实际上,平常写代码的时候,我们基本极少使用self,目前我接触到的基本知识中,只有在闭包中调用外部的属性或方法时,必须要使用self,其他时间基本没用过。教材中还有一种情况需要使用self,那就是局部变量和全局变量名字完全一样时,用self.属性名,会默认调用全局的那个属性。不过,这么坑爹的命名方法,真的有这么写的么 ㄟ(▔ ,▔)ㄏ ,看看代码这种命名方式吧:

    //  当全局属性和局部属性出现命名完全一样时,使用self加以区分。
    class MakeName 
    let firstString = "Hello"
    func printIntro() 
        let firstString = "World"
        print(firstString,self.firstString)
    
    
    let name = MakeName()
    name.printIntro()      //  输出  World Hello

    不知道注意了没,上面一直使用的类写的实例代码,而没有使用结构体和枚举,其实,真的不一样。。。已经说过,类是引用类型,尔机构体和枚举是值类型。一般情况下,值类型的属性是不能在它的实例方法中被修改的。但是,如果确实需要在结构体或者枚举的实例方法中修改内部属性值,那么可以选择 变异(mutating) 这个方法,然后就可以在实例方法中修改内部属性值了。这个修改并不是值拷贝,而是在原有的基础上修改数据。下面的示例代码中可以看出来这一点。
    要使用变异方法,将关键字 mutating 放到方法的关键字 func 之前就可以了:

    //  枚举、结构体修改内部属性值,以结构体为例
    struct ModifyProperties 
    var x = 0.0, y = 0.0
    mutating func movePoint(xChange changeX: Double, yChange changeY: Double) 
        x += changeX
        y += changeY
    
    
    //  实例并初始化
    var originalPoint = ModifyProperties(x: 2, y: 2)
    //  修改
    originalPoint.movePoint(xChange: 33, yChange: 66)
    //  查看现在 ModifyProperties 的属性值
    originalPoint.x      //  35
    originalPoint.y     //  68

    因为要修改结构体或者枚举内部属性值,并且结构体和枚举都是值类型,所以不能把结构体或者枚举设置为常量的实例方法,即不能用 let 修饰。否则会直接抛出错误。

    在可变方法中,可以给self,即类型本身赋值,这个以后会在枚举中经常用到。这次不用结构体做例子了,直接看枚举的用法吧,毕竟比结构体稍微复杂些:

    enum Volume 
    //  音量,低、正常、高
    case Low, Normal, Height
    //  修改自身值
    mutating func nextState() 
        switch self 
        case .Low:      self = .Normal
        case .Normal:   self = .Height
        case .Height:   self = .Low
        
    
    
    //  调用
    var volume = Volume.Low         //  volume = Low
    volume.nextState()              //  volume = Normal
    volume.nextState()              //  volume = Height
  2. 类型方法
    就是前言中那种简单地调用方式,教材中提供了一个挺长的示例代码,不过个人感觉并没有解释我想知道的:其实我最想知道的是什么时间用类型方法,什么时间用实例方法,是否和OC中的相似。这个相信会在以后的使用、学习中,慢慢了解的。刚才本来想Google下的,结果翻墙工具不好使了,访问不了,百度了下,也没太好的结果,有个博客把教材中的例子完全复制了,并且页面看起来很赏心悦目,可以去看看,点击查看 。下面我就用几行代码展示类型方法的基本使用吧。
    声明结构体和枚举的类型方法,在方法的func关键字前加上关键字static。类有些不同,类可能使用关键字来允许子类重写父类的实现方法。

    class SomeTypeClass 
    static var number = 0
    //  类有两种类型方法的定义样式,枚举和结构体只有关键字 static一种方式
    //  使用关键字 class
    class func counter() 
        number += 3
    
    //  使用关键字 static
    static func printDescrible() 
        print(number)
    
    
    //  调用类型方法
    SomeTypeClass.number         //  number = 0
    SomeTypeClass.counter()      //  number = 3
    SomeTypeClass.printDescrible()
  3. 如何线程安全的建立一个单例
    其实这个算是自己临时加的一个东西,毕竟这东西天天都在用,然而一段时间不写后,还是有点生僻的。先写个OC版的吧:

    //  线程安全创建单例
    + (ColorManager *)shareColorManger 
    static ColorManager *shareColorManagerInstance = nil;
    static dispatch_once_t predicate;
    dispatch_once(&predicate, ^
        shareColorManagerInstance = [[self alloc]init];
    );
    return shareColorManagerInstance;
    

    当项目中需要多次用到单例模式的时候,显然把单例模式的定义设置成一个宏定义,用的时候肯定会方便很多。这篇文章 详细的介绍了如何宏定义一个单例模式。因为符号 # 的问题,没法在这里看到示例代码了。其实Swift版的单例模式也是一样的吧……然而并不一样,这篇博客详细分析了从OC过渡到Swift的单例写法到最终的安全优美的Swift单例写法 ,博主真大神,涨了不少见识,最终的单例就是下面这种写法:

    //  Swift单例模式
        class Singleton 
            static let shareInstance = Singleton()
            private init()    //  这样就阻止了其他对象使用这个类的默认 “()” 初始化方法
        

结束语

随手一翻,就能找到一张有意思的壁纸。。。睡觉睡觉,瞌睡死了。

以上是关于Swift-方法(Methods)的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift 中结束 CAEmitterLayer 的正确方法是啥?

Swift4 方法,文档代码

Python笔记 · 魔法函数 / Magic Methods / Dunder Methods

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

Swift学习第五枪

学习Swift -- 继承