Swift中一些常见的关键字一(inout,defer,throw等)

Swift关键字

Swift从1.0开始一直迭代到如今的4.0,出现了很多关键字。这些关键字,有的帮助我们处理了一些复杂的代码结构设计,有的帮助我们简化了许多代码。这帮助我们提高了开发的效率和降低了维护成本,所以我们做代码优化的时候,应该优先考虑到使用合适的关键字。Swift中各种关键字很多,这篇文章,就一些常用的关键字做一点介绍。

本文将 inout,defer,throws,rethrows这几个关键字进行介绍。

inout

inout关键字用一句话概括:将值类型的对象用引用的方式传递。
我们经常说值类型引用类型实际上就是指对象的传递方式分别是 按值传递按址传递
值类型 按值传递:

let a: Int = 5
var b: Int = a
b = b+1 
print(a,b)    //    5,6

引用类型(class对象) 按址传递

let p1 = Person()
P1.name = "name1"
let p2 = p1
p2.name = "name2"
print(p1.name,p2.name)   // name2, name2

inout关键字则可以使得值类型的对象和引用类型的对象一样,以按址传递的方式进行操作,这里的操作不仅包含上述例子中的赋值操作,也包含了函数的参数传递行为。
通俗的举个例子:我们在使用函数传递一个Int类型对象的时候,通常会将这个对象的值传递进去了。但是如果使用inout修饰对象的类型,则可以将变量的地址传入函数。就像下面这个handle函数一样。

func test(){
    var a:Int = 5
    handle(a:&a)   //  注意这里使用了取址操作
    print(a)    // 6  
}

func handle(a:  inout Int){
    print(a)   
    a = a + 1     //如果没有inout修饰的话,这句代码将会报错,主要意思是不能改变一个let修饰的常量。
}

最终,我们在test 函数中打印的变量a的值被改变了。
除了 Int类型,诸如:CGFloat,Bool,Character,Array,struct等,这些值类型的对象都可以使用inout修饰,达到使用引用的方式传递的目的。

defer

defer关键字用一句话概括:修饰一段函数内任一段代码,使其必须在函数中的其余代码都执行完毕,函数即将结束前调用。也可以理解成将延迟执行。
为了更好的了解defer的作用,我写了一段代码:

func test(){
   print("函数开始")
   defer{
       print("执行defer1")
   }
   print("函数将结束")
   defer{
       print("执行defer2")
   }
}

test()
打印   //   
函数开始
函数将结束
执行defer2
执行defer1

我在test函数中,添加了两个 defer,分别打印了两条语句。从下面的打印中,可以看到,两个defer都执行了。并且他们都在函数结束之后执行的:defer总在函数要结束之前调用,尽管我将它们放在了程序较靠前的位置
defer2先于defer1执行,说明如果一个函数中包含数个defer 的话:程序会按照自下而上的顺序执行defer
以上是在一个同步的代码中运行的defer,那如果是异步执行的代码defer的作用又是怎样的呢?

    func test(){
        print("函数开始")
        defer{
            print("执行defer1")
        }
        defer{
            print("执行defer2")
        }
        DispatchQueue.main.asyncAfter(deadline: .now()+1) {
            print("异步执行完毕")
        }
        print("函数将结束")
    }

test()
打印:
函数开始
函数将结束
执行defer2
执行defer1
异步执行完毕

异步代码的执行,不会影响defer的执行时间。事实上,defer的执行只和其所在的作用域有关,如果作用域即将被回收,那么会在回收之前执行defer

throws

Swift要求的严格的类型安全,我想它对于错误的处理也不太可能马虎吧。回想在OC中,使用NSError处理错误,而实际上NSError处理的错误有限,我们不太可能在日常所有的开发中使用NSError,通常,对于一个需要进行错误处理的时候,我们习惯性使用一个 nil作为参数,就像这样:

    [[NSFileManager defaultManager] contentsOfDirectoryAtURL:@"aURL" 
includingPropertiesForKeys:@"aKey" options:nil error:nil];

因为类似的错误出现的情况是很极端的场景,大多数时候使用nil是没有问题的。但是,这是一个隐患,不仅不能回馈错误,还增加了维护的成本:至少我得知道这个函数究竟在哪些极端情况下才会返回错误! 而这一切是因为程序员的懒或者马虎造成的,Swift决定从技术上解决这个问题:使用throw可以让程序员必须处理相关的异常代码!
Swift中提供了Error协议,我们在开发中,如果要自定义自己的错误类型,一般会使用一个Enum来继承Error协议,目的是享用Error已经包含的一些特性。
下面是一个例子:

//错误类型枚举
enum MyError : Error {
    case ErrorOne
    case ErrorTwo
    case ErrorThree
    case ErrorOther
}

func willThrow(_ type:NSInteger)throws -> NSString{
        print("开始处理错误")
        if type == 1 {
            throw MyError.ErrorTwo
        }else if type == 2 {
            throw MyError.ErrorTwo
        }else if type == 3{
            throw MyError.ErrorThree
        }else {
            throw MyError.ErrorOther
        }
        return "一切都很好"
    }
    
//调用
     do {
        let str = try self.willThrow(2)
            //以下是非错误时的代码
            print(str) //如果有错误出现,这里将不会执行
        }catch let err as MyError{
            print(err)
        }catch{
            //这里必须要携带一个空的catch 不然会报错。 原因是可能遗漏
      }
    打印//
    ErrorTwo

throws的使用很简单,只需要在可能出现异常的函数或者方法后面添加throws。
经过这个关键字修饰的函数,在调用的时候,需要程序员加上do-catch来调用。
对于错误类型开发者来说,只需要使用Throws进行修饰,就保证了以后的调用者必然需要对相应的错误进行处理(当然也可以不处理,但无论如何,错误被throw携带出来了,以后的维护和优化不需要重新做错误处理的设计,直接加上错误处理的逻辑即可)。

rethrows

rethrows是异常往上传递的关键字。上面说了throws用在可能出现异常的函数或者方法中,而rethrows针对的不是函数或者方法的本身,而是它携带的闭包类型的参数,当它的闭包类型的参数throws的时候,我们要使用rethrows继续将这个异常往上传递, 直到被调用者使用到。这相比throws多一个传递的环节。
还是同样,使用一个简单的例子来看一看:

    func willThrow(_ type:Int)throws -> String{
        
        print("开始处理错误")
        if type == 1 {
            print("成功")
        }else if type == 2 {
            throw MyError.ErrorTwo
        }else if type == 3{
            throw MyError.ErrorThree
        }else {
            throw MyError.ErrorOther
        }
        return "一切都很好"
    }
    

    func willRethrow(_ throwCall:(Int) throws ->String) rethrows {
      
        do {
           let result = try throwCall(2)  
            print(result)
        } catch let err as MyError{
            throw err    //这里进行了 再次throw
        }catch{
            
        }
    }

//调用
       let afunc = self.willThrow
        
        do {
            try self.willRethrow(afunc)
        } catch let err as MyError {
            print("rethorws ",err)
        }catch{
            
        }

 打印 //
  rethorws  ErrorTwo

代码中看到,willRethrow本身并不对错误进行处理,原因是它本身并不会差生错误。另外的,它的参数throwCall进行了错误的处理,willRethrow对throwCall的错误进行再次throw。
简单来说,rethorws就是throws的传递,也即是对于throw的一个层次级别的应用。我们甚至可以进行多级传递,但是会导致代码过于复杂,不建议这么做。

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