Swift源码(Alamofire)学习之错误处理篇(AFError)

从AFError看Swift枚举用法

女儿惹她妈妈生气了,我让她去道歉。
“知错就改,快去找你妈,认错。”我催促她。
小家伙犹豫了半天,终于走进了厨房,对她妈说道:
“妈妈,请问你是刘亦菲吗?”
妻子很疑惑:“不是啊。”
“哦,对不起,我认错了。”


枚举为一组相关值定义了一个公共类型,使您能够在代码中以类型安全的方式处理这些值。(Apple官方文档的定义)


举个🍐

enum ADayWork {
case watchNews
case listenMusic
case napp
case chat
case code
}

let now = ADayWork.napp

switch now {
case .watchNews:
    print("我正在刷头条")
case .listenMusic:
    print("哼哼哈嘿,快使用双节棍")
case .napp:
    print("我刚干啥了又")
case .chat:
    print("这个妹子怎么不回我啊")
case .code:
    print("这需求,我擦,找找网上有没有类似的轮子")
}

上面基本是我们通常的用法,定义一组具有相关性的值,使用的时候进行相应的处理。但是,如果只是这样使用,那真是浪费了Swift把它提升为一等公民的良苦用心了

在Swift中你可以定义Swift枚举以存储任何给定类型的关联值,并且如果需要,每种枚举情况的值类型可以不同。

紧随上面的🍐

enum ADayWork {
        enum Mood:String{
            case happy = "哈哈哈"
            case bored = "无聊"
            case anger = "ca"
        }
        
        
        case napp(minutes:Int)
        case chat(friendName:String)
        case listenMusic(musicName:String,singer:String,player:String)
        case code(mood:Mood)
        ///函数也是一等公民了,现在也可以当做参数和返回值了
        case watchNews(pagesName:String,feeling:((Mood) -> ()))
    
    }
    let napp = ADayWork.napp(minutes:30)
    
     let chat = ADayWork.chat(friendName:"刘亦菲")
    
    let listenMusic = ADayWork.listenMusic(musicName: "双节棍", singer: "周杰伦", player: "QQ音乐")     
    
    let code = ADayWork.code(mood:.happy)
    
    let watchNews = ADayWork.watchNews(pagesName: "今日头条") { (mood) in
        print("\(mood.rawValue)")
    }
    let arr:[ADayWork] = [napp,chat,listenMusic,code,watchNews]
    
    for doWhat in arr {
        switch doWhat {
        case .napp(let minute):
            print("我刚发呆了\(minute)分钟")
        case .chat(let friendName):
            print("我在和\(friendName)聊骚")
        case .listenMusic(let musicName,let singer,let player):
            print("我正在用\(player) 听 \(singer) 唱的 \(musicName) 哎呦不错哦")
        case .code(let mood):
            print("这需求,我擦,找找网上有没有类似的轮子,找到了,\(mood)")
        case .watchNews(let pageNames,let feeling):
            print("我在用\(pageNames)刷新闻")
            feeling(.happy)
        }
    }
    
    
输出结果:
我刚发呆了30分钟
我在和刘亦菲聊骚
我正在用QQ音乐 听 周杰伦 唱的 双节棍 哎呦不错哦
这需求,我擦,找找网上有没有类似的轮子,找到了,happy
今日头条
感觉很happy

灵儿我来啦

image

你可以选择存储任意类型的关联值,这就大大拓展了枚举的应用场景了。

当然这里我只是列举了下枚举关联值的基本用法,想要详细了解枚举的话,可以参考这篇文章


AFError中对枚举的用法

错误类型

AFError中将错误定义成了五个大类型

image
  • invalidURL-无效的URL
    关联值类型是URLConvertible,这是一个协议,定义了方法func asURL() throws -> URL,协议下面有几个实现
    image

    通过String,URL,URLComponents的实现可以看出这个协议的作用是可以转换任意类型为URL类型,从而方便使用。而关联这个类型的值目的是为了当URL无效的时候,可以通过关联值获取到,然后进行打印等操作。

比如

    ///声明结构体,或者其他任意类型都行
    struct Dog {
        var dogName:String = ""
    }
    ///只要实现了协议URLConvertible的方法
    extension Dog:URLConvertible{
        public func asURL() throws -> URL {
            guard let url = URL(string: self.dogName) else
            {
             ///失败的话则抛出异常,并且将urlString关联在枚举值中
                throw AFError.invalidURL(url: self.dogName)
            }
         return url
        }
    }   
    ///使用 - 这里如果失败的话就会捕获到invalidURL这个异常,并且可以获取到错误的url
    let url = try Dog().asURL()

其实这里可以看出协议的好处了,特别是 Swift 支持拓展协议,任意的类型,只要实现了相应的协议,就拥有了相应的功能。后面会再分析下 Swift 面向协议的写法。

这里推荐一本书 - Swift面向协议编程

image

另外两本书我还没看,不过感觉应该也还不错。千万不要找那些什么多少天精通,什么从基础到高深。除非你是小白。

看来之后你就会发现,还要啥对象啊。自己一个人不好玩么?


  • parameterEncodingFailed-参数编码失败

    关联值类型是ParameterEncodingFailureReason,这又是一个枚举,列举了可能会导致参数编码失败的原因。

    1. missingURL - urlRequest.url不存在
    2. jsonEncodingFailed(error: Error) - 参数编码成JSON失败
    3. propertyListEncodingFailed(error: Error) 参数编码成propertyList失败
  • multipartEncodingFailed-参数编码失败
    多部分编码错误一般发生在上传或下载请求中对数据的处理过程中,这里边最重要的是对上传数据的处理过程

  • responseValidationFailed-参数编码失败
    Alamofire不管请求是否成功,都会返回response。它提供了验证ContentType和StatusCode的功能

  • responseSerializationFailed-参数编码失败
    Alamofire支持把服务器的response序列化的时候发生的错误

由于我们这里主要关注AFError对于枚举的使用,所以这些错误类型我就不一一翻译了。

错误快速定位判断

在源码中我们可以发现

extension AFError {
    /// Returns whether the AFError is an invalid URL error.
    public var isInvalidURLError: Bool {
        if case .invalidURL = self { return true }
        return false
    }

    /// Returns whether the AFError is a parameter encoding error. When `true`, the `underlyingError` property will
    /// contain the associated value.
    public var isParameterEncodingError: Bool {
        if case .parameterEncodingFailed = self { return true }
        return false
    }

这里通过对枚举拓展了计算属性,来直接对错误类型进行if判断,不用在switch一个一个判断了。

let err = AFError.invalidURL(url: Dog.init(dogName:"123"))
if err. isInvalidURLError {
    print("我只关注这个错误是不是url错了,是啥错误类型我不关心")
}

一些比较方便的计算属性

extension AFError {

/// The `URL` associated with the error.
public var url: URL? {
    switch self {
    case .multipartEncodingFailed(let reason):
        return reason.url
    default:
        return nil
    }
}

/// The `Error` returned by a system framework associated with a `.parameterEncodingFailed`,
/// `.multipartEncodingFailed` or `.responseSerializationFailed` error.
public var underlyingError: Error? {
    switch self {
    case .parameterEncodingFailed(let reason):
        return reason.underlyingError
    case .multipartEncodingFailed(let reason):
        return reason.underlyingError
    case .responseSerializationFailed(let reason):
        return reason.underlyingError
    default:
        return nil
    }
}

当我们不想switch一个一个判断错误类型,并且我们知道这个错误是什么类型的时候,我们就可以直接.属性,来直接定位到精准的错误信息

let err = AFError.invalidURL(url: Dog.init(dogName:"123"))   
print("我知道这个错误是url错误了,现在他的错误的url是\(err. url)")

错误描述

通过实现LocalizedError这个协议并且实现它的计算属性errorDescription,针对不同的错误来分别进行错误信息的描述。

这里的代码结构十分清晰,针对每个枚举的错误定义localizedDescription计算属性并返回错误描述。大家可以仔细品味下。

最终

感觉挺啰嗦,但是好像又没真正的讲解好,大家如果有什么意见的话可以提出来,一起学习,共同进步。

不过真正写出来了感觉对枚举的值类型应用的确加深了一层理解。希望大家以后也可以不仅是看,也要写。

联系方式

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