Swift Error重构优化详解
目录
背景现状
项目每积累到一定程度,代码的重构优化是必经之路。
试卷项目初期,整体错误Code较少,直接使用更便于处理错误状态,因此便全部归整到一个单独的 中,但是随着项目功能的丰富,各个功能模块越来越多,模块错误的处理也各不相同,每个模块都关联了所有的错误Code,后续还会持续增长,导致越来越难以维护。
enum ResponseCodeType: Int {
case success = 0
case tokenExpire = 11001
case overVerifyCode = 11011
case verifyCodeExpire = 11002
case verifyCodeIncorrect = 11003
case autoLoginFailed = 11004
case appidLoginFailed = 11005
case phoneIsRegisted = 11006
case phoneHasBinded = 11010
case joinedBeePlan = 11100002
case uploadRepeate = 11020005
case wechatHasBinded = 11010017
case phoneHasBindedOtherWeChat = 11010022
case todayIsSignIned = 11140003
case subjectCountLimit = 11150004
case invalidTagName = 11160002
case alreadyExistsTagName = 11160003
case outOfMaxTagsCount = 11160004
case notRegisterHomework = 11010033
case notSupportNumber = 11010028
case wrongTeamCode = 11210005
case classNotFound = 11210006
case nicknameExists = 11210007
case joinClassThreeTimes = 11210008
case identityNickNameExists = 11210014
case checkClassCodeMax = 11210016
case createClassMAx = 11210015
case joinTeamMax = 11210017
case studentCountMax = 11210018
case other = -99999
}
问题分析
提前分析、明确目标。
期望结果
技术选型
根据期望结果,可以大致选定技术方向
优化解决
前后对比,不断调优。
Error模型
优化前
struct NetWorkError: Error {
var code: ResponseCodeType = .other
var msg: String { code.errorString }
}
优化后
/// 错误类型描述
public protocol ISErrorProtocol {
var errorString: String { get }
}
public enum ModuleRespError
/// 对应模块自定义类型code
case type(_ value: T)
/// 基类请求code
case baseType(_ value: ResponseCodeType)
/// 错误提示归整
public var mapErrorString: String {
switch self {
case .type(let value):
return value.errorString
case .baseType(let value):
return value.errorString
}
}
}
基类Request
使用协议的类型占位符 associatedtype,便于后续进行 rawValue 的枚举映射
在ISTargetType协议中关联错误码类型
public protocol ISTargetType {
/// 错误码类型,由各模块自定义
associatedtype ErrorCodeType: RawRepresentable
}
优化前
/// 根据 ISTargetType 枚举类型调用接口,返回 model
static func requestISType
completion: @escaping (_ model: NetworkModelResponse?, _ code: ResponseCodeType) -> Void) {
// ...
Network.IS.fetchDataDic(server) { dataDic in
guard let dataDic = dataDic,
let model: NetWorkResponseModel = NetWorkResponseModel.deserialize(from: dataDic) else {
completion(nil, .other)
return
}
// 判断code 是否为token过期
let codeValue = model.ret ?? ResponseCodeType.other.rawValue
// errorType
let codeType = ResponseCodeType(rawValue: codeValue) ?? .other
// 基类Code处理,token过期
NetWorkRequest.checkTokenDidExpire(codeType)
// 抛出的code:基类、模块混在一起
completion(model, codeType)
}
}
优化后
/// T.ErrorCodeType: 遵循 RawRepresentable 协议的泛型
/// Result
static func requestISResultType
result: @escaping ((Result
// ...
Network.IS.fetchDataDic(server) { dataDic in
// 接口数据处理
guard let dataDic = dataDic,
let model: NetWorkResponseModel = NetWorkResponseModel.deserialize(from: dataDic),
let retCode = model.ret else {
// 接口错误,默认基类错误
let error: ModuleRespError
result(.failure(error))
return
}
if retCode == 0 {
// 成功返回
result(.success(model))
return
}
// 请求失败
if let baseType = ResponseCodeType(rawValue: retCode) {
result(.failure(.baseType(baseType)))
// 优先处理基类错误code,例如 token失效
NetWorkRequest.checkTokenDidExpire(baseType)
} else if let retValue = retCode as? T.ErrorCodeType.RawValue,
let moduleType = T.ErrorCodeType(rawValue: retValue) {
// 解析并返回模块错误码
result(.failure(.type(moduleType)))
}
}
}
模块调用
优化前
public func queryDemo(with params: [String: String], completionHandler: @escaping (_ model: DemoModel?, _ code: ResponseCodeType) -> Void) {
NetWorkRequest.requestISType(GroupQueryServer.createGroup(params)) { model in
// ...
let code = model.ret ?? -1
let type = ResponseCodeType(rawValue: code) ?? .other
guard type == .success,
let result = DemoModel.deserialize(from: model.data) else {
completionHandler(nil, type)
return
}
completionHandler(.success(resultModel))
}
}
logic.queryDemo(with: params) { model, code in
// 只能通过解包model来判断接口的成功或失败
guard let model = model else {
// 失败处理
handleFail(code: code)
return
}
// 成功处理
hanldeSuccess()
}
private func handleFail(code: ResponseCodeType) {
// ...
// 当前模块错误处理
let showWarning = code == .wrongTeamCode || code == .classNotFound
// UI处理
warningLabel.isHidden = !showWarning
// 提示
CEProgressHUD.showTextHUD(code.errorString)
}
优化后
public enum StudyGroupRespCode: Int, ISErrorProtocol {
case wrongTeamCode = 11210005
case classNotFound = 11210006
case nicknameExists = 11210007
case joinClassThreeTimes = 11210008
case identityNickNameExists = 11210014
case checkClassCodeMax = 11210016
case createClassMAx = 11210015
case joinTeamMax = 11210017
case studentCountMax = 11210018
case folderLevelLimit = 11210027
case curIdentifierError = 11210011
case clockFrequencyInvalid = 11210036
case other
}
public func queryDemo(with params: [String: String], completionHandler: @escaping ((Result
// 基类请求
NetWorkRequest.requestISResultType(GroupQueryServer.createGroup(params)) { result in
switch result {
case .success(let success):
// 结果处理que
if let resultModel = ClassItemModel.deserialize(from: success.data) {
// 转换模块模型model
completionHandler(.success(resultModel))
} else {
// 转化失败,默认other
completionHandler(.failure(.type(.other)))
}
case .failure(let error):
// 抛出的模块错误
completionHandler(.failure(error))
}
}
logic.queryDemo(with: params) { result in
// 通过 Result 划分结果状态
switch result {
case .success(let model):
// 成功处理
hanldeSuccess()
case .failure(let error):
// 失败处理
handleError(error)
}
}
// 示例为简单处理,若需精细化处理错误,拆分优化后的代码,逻辑明显更加清晰
private func handleError(_ error: ModuleRespError
switch error {
case .type(let code):
// ...
// 当前模块错误处理
let showWarning = code == .wrongTeamCode || code == .classNotFound
// UI处理
warningLabel.isHidden = !showWarning
// 提示
CEProgressHUD.showTextHUD(code.errorString)
case .baseType(let error):
// 基类错误处理
CEProgressHUD.showTextHUD(error.errorString)
}
}
总结
至此,我们已经了解了有关ErrorCode的重构优化的大体逻辑,从后续的开发流程结果可以看出,确实对项目的Code混乱增长有了良好的控制,各模块只需要关注处理自己的异常code,降低了维护代码难度,后续也会持续关注和优化。
参考资料
以上就是Swift Error重构优化详解的详细内容,更多关于Swift Error重构优化的资料请关注脚本之家其它相关文章!
您可能感兴趣的文章: