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: Error {

  /// 对应模块自定义类型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(_ server: T,

  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(_ server: T,

  result: @escaping ((Result>) -> Void)) {

  // ...

  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 = .baseType(.other)

  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>) -> Void)) {

  // 基类请求

  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重构优化的资料请关注脚本之家其它相关文章!

  您可能感兴趣的文章:

您可能感兴趣的文章:

相关文章