美文网首页
Swift源码(Alamofire)学习之错误处理篇(AFErr

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

作者: Lucas汪星人 | 来源:发表于2018-08-09 12:35 被阅读111次

    从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计算属性并返回错误描述。大家可以仔细品味下。

    最终

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

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

    联系方式

    相关文章

      网友评论

          本文标题:Swift源码(Alamofire)学习之错误处理篇(AFErr

          本文链接:https://www.haomeiwen.com/subject/atbqbftx.html