Alamofire源码解读系列之错误处理(AFError)
2018-01-31 00:00
615 查看
1.正常用法
enumMovement{
caseLeft
caseRight
caseTop
caseBottom
}
letaMovement=Movement.Left
switchaMovement{
case.Left:
print("left")
default:
print("Unknow")
}
ifcase.Left=aMovement{
print("Left")
}
if.Left==aMovement{
print("Left")
}
2.声明为整型
enumSeason:Int{
caseSpring=0
caseSummer=1
caseAutumn=2
caseWinter=3
}
3.声明为字符串类型
enumHouse:String{
caseZhangSan="Iamzhangsan"
caseLiSi="Iamlisi"
}
letzs=House.ZhangSan
print(zs.rawValue)
enumCompassPoint:String{
caseNorth,South,East,West
}
letn=CompassPoint.North
print(n.rawValue)
lets=CompassPoint(rawValue:"South");
4.声明为浮点类型
enumConstants:Double{
caseπ=3.14159
casee=2.71828
caseφ=1.61803398874
caseλ=1.30357
}
letpai=Constants.π
print(pai.rawValue)
5.其他类型
enumVNodeFlags:UInt32{
caseDelete=0x00000001
caseWrite=0x00000002
caseExtended=0x00000004
caseAttrib=0x00000008
caseLink=0x00000010
caseRename=0x00000020
caseRevoke=0x00000040
caseNone=0x00000080
}
6.enum包含enum
enumCharacter{
enumWeapon{
caseBow
caseSword
caseLance
caseDagger
}
enumHelmet{
caseWooden
caseIron
caseDiamond
}
caseThief
caseWarrior
caseKnight
}
letcharacter=Character.Thief
letweapon=Character.Weapon.Bow
lethelmet=Character.Helmet.Iron
7.结构体和枚举
structScharacter{
enumCharacterType{
caseThief
caseWarrior
caseKnight
}
enumWeapon{
caseBow
caseSword
caseLance
caseDagger
}
lettype:CharacterType
letweapon:Weapon
}
letsc=Scharacter(type:.Thief,weapon:.Bow)
print(sc.type)
8.值关联
enumTrade{
caseBuy(stock:String,amount:Int)
caseSell(stock:String,amount:Int)
}
lettrade=Trade.Buy(stock:"Car",amount:100)
ifcaseletTrade.Buy(stock,amount)=trade{
print("buy\(amount)of\(stock)")
}
enumTrade0{
caseBuy(String,Int)
caseSell(String,Int)
}
lettrade0=Trade0.Buy("Car0",100)
ifcaseletTrade0.Buy(stock,amount)=trade0{
print("buy\(amount)of\(stock)")
}
9.枚举中的函数
enumWearable{
enumWeight:Int{
caseLight=2
}
enumArmor:Int{
caseLight=2
}
caseHelmet(weight:Weight,armor:Armor)
funcattributes()->(weight:Int,armor:Int){
switchself{
case.Helmet(letw,leta):
return(weight:w.rawValue*2,armor:a.rawValue*4)
}
}
}
lettest=Wearable.Helmet(weight:.Light,armor:.Light).attributes()
print(test)
enumDevice{
caseiPad,iPhone,AppleTV,AppleWatch
funcintroduced()->String{
switchself{
case.AppleTV:return"\(self)wasintroduced2006"
case.iPhone:return"\(self)wasintroduced2007"
case.iPad:return"\(self)wasintroduced2010"
case.AppleWatch:return"\(self)wasintroduced2014"
}
}
}
print(Device.iPhone.introduced())
10.枚举中的属性
enumDevice1{
caseiPad,iPhone
varyear:Int{
switchself{
case.iPad:
return2010
case.iPhone:
return2007
}
}
}
letiPhone=Device1.iPhone
print(iPhone.year)
ParameterEncodingFailureReason
通过publicenumAFError:Error{
///Theunderlyingreasontheparameterencodingerroroccurred.
///
///-missingURL:TheURLrequestdidnothaveaURLtoencode.
///-jsonEncodingFailed:JSONserializationfailedwithanunderlyingsystemerrorduringthe
///encodingprocess.
///-propertyListEncodingFailed:Propertylistserializationfailedwithanunderlyingsystemerrorduring
///encodingprocess.
publicenumParameterEncodingFailureReason{
casemissingURL
casejsonEncodingFailed(error:Error)
casepropertyListEncodingFailed(error:Error)
}
}
letparameterErrorReason=AFError.ParameterEncodingFailureReason.missingURL
枚举的访问是一级一级进行的。我们再看这行代码:
参数编码有一下几种方式:
把参数编码到URL中
把参数编码到httpBody中
Alamofire中是如何进行参数编码的,这方面的内容会在后续的
综上所述,
MultipartEncodingFailureReason
publicenumMultipartEncodingFailureReason{
casebodyPartURLInvalid(url:URL)
casebodyPartFilenameInvalid(in:URL)
casebodyPartFileNotReachable(at:URL)
casebodyPartFileNotReachableWithError(atURL:URL,error:Error)
casebodyPartFileIsDirectory(at:URL)
casebodyPartFileSizeNotAvailable(at:URL)
casebodyPartFileSizeQueryFailedWithError(forURL:URL,error:Error)
casebodyPartInputStreamCreationFailed(for:URL)
caseoutputStreamCreationFailed(for:URL)
caseoutputStreamFileAlreadyExists(at:URL)
caseoutputStreamURLInvalid(url:URL)
caseoutputStreamWriteFailed(error:Error)
caseinputStreamReadFailed(error:Error)
}
多部分编码错误一般发生在上传或下载请求中对数据的处理过程中,这里边最重要的是对上传数据的处理过程,会在后续的
综上所述,这些错误基本上都跟数据的操作相关,这个在后续会做出很详细的说明。
ResponseValidationFailureReason
publicenumResponseValidationFailureReason{
casedataFileNil
casedataFileReadFailed(at:URL)
casemissingContentType(acceptableContentTypes:[String])
caseunacceptableContentType(acceptableContentTypes:[String],responseContentType:String)
caseunacceptableStatusCode(code:Int)
}
Alamofire不管请求是否成功,都会返回response。它提供了验证ContentType和StatusCode的功能,关于验证,再后续的文章中会有详细的解答,我们先看看这些原因:
ResponseSerializationFailureReason
publicenumResponseSerializationFailureReason{
caseinputDataNil
caseinputDataNilOrZeroLength
caseinputFileNil
caseinputFileReadFailed(at:URL)
casestringSerializationFailed(encoding:String.Encoding)
casejsonSerializationFailed(error:Error)
casepropertyListSerializationFailed(error:Error)
}
我们在
response直接返回HTTPResponse,未序列化
responseData序列化为Data
responseJSON序列化为Json
responseString序列化为字符串
responsePropertyList序列化为Any
那么在序列化的过程中,很可能会发生下边的错误:
AFError
上边内容中介绍的那么最重要的问题就是,如何把上边4个独立的枚举进行串联呢?Alamofire巧妙的地方就在这里,有4个独立的枚举,分别代表4大错误。也就是说这个网络框架肯定有这4大错误模块,我们只需要给AFError设计4个子选项,每个子选项关联上上边4个独立枚举的值就ok了。
这个设计真的很巧妙,试想,如果把所有的错误都放到AFError中,就显得非常冗余。那么下边的代码就呼之欲出了,大家好好体会体会在swift下这么设计的妙用:
caseinvalidURL(url:URLConvertible)
caseparameterEncodingFailed(reason:ParameterEncodingFailureReason)
casemultipartEncodingFailed(reason:MultipartEncodingFailureReason)
caseresponseValidationFailed(reason:ResponseValidationFailureReason)
caseresponseSerializationFailed(reason:ResponseSerializationFailureReason)
AFError的扩展
也许在开发中,我们完成了上边的代码就认为够用了,但对于一个开源框架而言,远远是不够的。我们一点点进行剖析:现在给定一条数据:
funcfindErrorType(error:AFError){
}
我只需要知道这个error是不是参数编码错误,应该怎么办?因此为AFError提供5个布尔类型的属性,专门用来获取当前的错误是不是某个指定的类型。这个功能的实现比较简单,代码如下:
extensionAFError{
///ReturnswhethertheAFErrorisaninvalidURLerror.
publicvarisInvalidURLError:Bool{
ifcase.invalidURL=self{returntrue}
returnfalse
}
///ReturnswhethertheAFErrorisaparameterencodingerror.When`true`,the`underlyingError`propertywill
///containtheassociatedvalue.
publicvarisParameterEncodingError:Bool{
ifcase.parameterEncodingFailed=self{returntrue}
returnfalse
}
///ReturnswhethertheAFErrorisamultipartencodingerror.When`true`,the`url`and`underlyingError`properties
///willcontaintheassociatedvalues.
publicvarisMultipartEncodingError:Bool{
ifcase.multipartEncodingFailed=self{returntrue}
returnfalse
}
///Returnswhetherthe`AFError`isaresponsevalidationerror.When`true`,the`acceptableContentTypes`,
///`responseContentType`,and`responseCode`propertieswillcontaintheassociatedvalues.
publicvarisResponseValidationError:Bool{
ifcase.responseValidationFailed=self{returntrue}
returnfalse
}
///Returnswhetherthe`AFError`isaresponseserializationerror.When`true`,the`failedStringEncoding`and
///`underlyingError`propertieswillcontaintheassociatedvalues.
publicvarisResponseSerializationError:Bool{
ifcase.responseSerializationFailed=self{returntrue}
returnfalse
}
}
总而言之,这些都是给AFError这个枚举扩展的属性,还包含下边这些属性:
///The`URLConvertible`associatedwiththeerror.
publicvarurlConvertible:URLConvertible?{
switchself{
case.invalidURL(leturl):
returnurl
default:
returnnil
}
}
///The`URL`associatedwiththeerror.
publicvarurl:URL?{
switchself{
case.multipartEncodingFailed(letreason):
returnreason.url
default:
returnnil
}
}
///The`Error`returnedbyasystemframeworkassociatedwitha`.parameterEncodingFailed`,
///`.multipartEncodingFailed`or`.responseSerializationFailed`error.
publicvarunderlyingError:Error?{
switchself{
case.parameterEncodingFailed(letreason):
returnreason.underlyingError
case.multipartEncodingFailed(letreason):
returnreason.underlyingError
case.responseSerializationFailed(letreason):
returnreason.underlyingError
default:
returnnil
}
}
///Theresponse`Content-Type`ofa`.responseValidationFailed`error.
publicvarresponseContentType:String?{
switchself{
case.responseValidationFailed(letreason):
returnreason.responseContentType
default:
returnnil
}
}
///Theresponsecodeofa`.responseValidationFailed`error.
publicvarresponseCode:Int?{
switchself{
case.responseValidationFailed(letreason):
returnreason.responseCode
default:
returnnil
}
}
///The`String.Encoding`associatedwithafailed`.stringResponse()`call.
publicvarfailedStringEncoding:String.Encoding?{
switchself{
case.responseSerializationFailed(letreason):
returnreason.failedStringEncoding
default:
returnnil
}
}
这里是一个小的分割线,在上边属性的获取中,也是用到了下边代码中的扩展功能:
extensionAFError.ParameterEncodingFailureReason{
varunderlyingError:Error?{
switchself{
case.jsonEncodingFailed(leterror),.propertyListEncodingFailed(leterror):
returnerror
default:
returnnil
}
}
}
extensionAFError.MultipartEncodingFailureReason{
varurl:URL?{
switchself{
case.bodyPartURLInvalid(leturl),.bodyPartFilenameInvalid(leturl),.bodyPartFileNotReachable(leturl),
.bodyPartFileIsDirectory(leturl),.bodyPartFileSizeNotAvailable(leturl),
.bodyPartInputStreamCreationFailed(leturl),.outputStreamCreationFailed(leturl),
.outputStreamFileAlreadyExists(leturl),.outputStreamURLInvalid(leturl),
.bodyPartFileNotReachableWithError(leturl,_),.bodyPartFileSizeQueryFailedWithError(leturl,_):
returnurl
default:
returnnil
}
}
varunderlyingError:Error?{
switchself{
case.bodyPartFileNotReachableWithError(_,leterror),.bodyPartFileSizeQueryFailedWithError(_,leterror),
.outputStreamWriteFailed(leterror),.inputStreamReadFailed(leterror):
returnerror
default:
returnnil
}
}
}
extensionAFError.ResponseValidationFailureReason{
varacceptableContentTypes:[String]?{
switchself{
case.missingContentType(lettypes),.unacceptableContentType(lettypes,_):
returntypes
default:
returnnil
}
}
varresponseContentType:String?{
switchself{
case.unacceptableContentType(_,letresponseType):
returnresponseType
default:
returnnil
}
}
varresponseCode:Int?{
switchself{
case.unacceptableStatusCode(letcode):
returncode
default:
returnnil
}
}
}
extensionAFError.ResponseSerializationFailureReason{
varfailedStringEncoding:String.Encoding?{
switchself{
case.stringSerializationFailed(letencoding):
returnencoding
default:
returnnil
}
}
varunderlyingError:Error?{
switchself{
case.jsonSerializationFailed(leterror),.propertyListSerializationFailed(leterror):
returnerror
default:
returnnil
}
}
}
错误描述
在开发中,如果程序遇到错误,我们往往会给用户展示更加直观的信息,这就要求我们把错误信息转换成易于理解的内容。因此我们只要实现LocalizedError协议就好了。这里边的内容很简单,在这里就直接把代码写上了,不做分析:extensionAFError:LocalizedError{
publicvarerrorDescription:String?{
switchself{
case.invalidURL(leturl):
return"URLisnotvalid:\(url)"
case.parameterEncodingFailed(letreason):
returnreason.localizedDescription
case.multipartEncodingFailed(letreason):
returnreason.localizedDescription
case.responseValidationFailed(letreason):
returnreason.localizedDescription
case.responseSerializationFailed(letreason):
returnreason.localizedDescription
}
}
}
extensionAFError.ParameterEncodingFailureReason{
varlocalizedDescription:String{
switchself{
case.missingURL:
return"URLrequesttoencodewasmissingaURL"
case.jsonEncodingFailed(leterror):
return"JSONcouldnotbeencodedbecauseoferror:\n\(error.localizedDescription)"
case.propertyListEncodingFailed(leterror):
return"PropertyListcouldnotbeencodedbecauseoferror:\n\(error.localizedDescription)"
}
}
}
extensionAFError.MultipartEncodingFailureReason{
varlocalizedDescription:String{
switchself{
case.bodyPartURLInvalid(leturl):
return"TheURLprovidedisnotafileURL:\(url)"
case.bodyPartFilenameInvalid(leturl):
return"TheURLprovideddoesnothaveavalidfilename:\(url)"
case.bodyPartFileNotReachable(leturl):
return"TheURLprovidedisnotreachable:\(url)"
case.bodyPartFileNotReachableWithError(leturl,leterror):
return(
"ThesystemreturnedanerrorwhilecheckingtheprovidedURLfor"+
"reachability.\nURL:\(url)\nError:\(error)"
)
case.bodyPartFileIsDirectory(leturl):
return"TheURLprovidedisadirectory:\(url)"
case.bodyPartFileSizeNotAvailable(leturl):
return"CouldnotfetchthefilesizefromtheprovidedURL:\(url)"
case.bodyPartFileSizeQueryFailedWithError(leturl,leterror):
return(
"Thesystemreturnedanerrorwhileattemptingtofetchthefilesizefromthe"+
"providedURL.\nURL:\(url)\nError:\(error)"
)
case.bodyPartInputStreamCreationFailed(leturl):
return"FailedtocreateanInputStreamfortheprovidedURL:\(url)"
case.outputStreamCreationFailed(leturl):
return"FailedtocreateanOutputStreamforURL:\(url)"
case.outputStreamFileAlreadyExists(leturl):
return"AfilealreadyexistsattheprovidedURL:\(url)"
case.outputStreamURLInvalid(leturl):
return"TheprovidedOutputStreamURLisinvalid:\(url)"
case.outputStreamWriteFailed(leterror):
return"OutputStreamwritefailedwitherror:\(error)"
case.inputStreamReadFailed(leterror):
return"InputStreamreadfailedwitherror:\(error)"
}
}
}
extensionAFError.ResponseSerializationFailureReason{
varlocalizedDescription:String{
switchself{
case.inputDataNil:
return"Responsecouldnotbeserialized,inputdatawasnil."
case.inputDataNilOrZeroLength:
return"Responsecouldnotbeserialized,inputdatawasnilorzerolength."
case.inputFileNil:
return"Responsecouldnotbeserialized,inputfilewasnil."
case.inputFileReadFailed(leturl):
return"Responsecouldnotbeserialized,inputfilecouldnotberead:\(url)."
case.stringSerializationFailed(letencoding):
return"Stringcouldnotbeserializedwithencoding:\(encoding)."
case.jsonSerializationFailed(leterror):
return"JSONcouldnotbeserializedbecauseoferror:\n\(error.localizedDescription)"
case.propertyListSerializationFailed(leterror):
return"PropertyListcouldnotbeserializedbecauseoferror:\n\(error.localizedDescription)"
}
}
}
extensionAFError.ResponseValidationFailureReason{
varlocalizedDescription:String{
switchself{
case.dataFileNil:
return"Responsecouldnotbevalidated,datafilewasnil."
case.dataFileReadFailed(leturl):
return"Responsecouldnotbevalidated,datafilecouldnotberead:\(url)."
case.missingContentType(lettypes):
return(
"ResponseContent-Typewasmissingandacceptablecontenttypes"+
"(\(types.joined(separator:",")))donotmatch\"*/*\"."
)
case.unacceptableContentType(letacceptableTypes,letresponseType):
return(
"ResponseContent-Type\"\(responseType)\"doesnotmatchanyacceptabletypes:"+
"\(acceptableTypes.joined(separator:","))."
)
case.unacceptableStatusCode(letcode):
return"Responsestatuscodewasunacceptable:\(code)."
}
}
}
作者:老马的春天
链接:https://www.jianshu.com/p/99e6ba32f244
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
相关文章推荐
- Alamofire源码解读系列(二)之错误处理(AFError)
- Alamofire源码解读系列(二)之错误处理(AFError)
- Alamofire源码解读系列(三)之通知处理(Notification)
- Alamofire源码解读系列(二)之错误处理(AFError)
- Alamofire源码解读系列(一)之概述和使用
- Alamofire源码解读系列(九)之响应封装(Response)
- Alamofire源码解读系列(七)之网络监控(NetworkReachabilityManager)
- Alamofire源码解读系列(九)之响应封装(Response)
- Alamofire源码解读系列(五)之结果封装(Result)
- Alamofire源码解读系列(二)之错误处理(AFError)
- Alamofire源码解读系列(二)之错误处理(AFError)
- Alamofire源码解读系列(十二)之时间轴(Timeline)
- Alamofire源码解读系列(十二)之请求(Request)
- Alamofire源码解读系列(四)之参数编码(ParameterEncoding)
- 【dubbo源码解读系列】之五 rpc 处理类 DubboProtocol
- Tomcat源码解读系列三Tomcat对HTTP请求处理的整体流程
- iOS之AFN错误代码1016(Error Domain=com.alamofire.error.serialization.response Code=-1016 "Request failed: unacceptable)
- iOS 使用AFNetworking遇到错误 Error Domain=com.alamofire.error.serialization.response Code=-1016
- PHP源码安装mcrypt扩展error: ‘PHP_FE_END’ undeclared here (not in a function)错误处理
- Tomcat源码解读系列——Tomcat对HTTP请求处理的整体流程