Swift - 将通用代码重构为协议
Swift - refactoring common code to a protocol
我有多个 class 具有调用公共网络 class 进行 GET api 调用的代码。下面是一个例子:
public typealias Api1Result = (Result<Api1Model>) -> Void
private var path = "the/path/api1"
public enum Api1ServiceError: String, Error {
case error = "Sorry, the api1 service returned something different than expected"
}
extension Api1Model {
public static func getApi1(networkClient: NetworkClient = networkClient, completion: @escaping Api1Result) {
networkClient.getPath(path) { result in
switch result {
case .success(let data):
do {
let api1Model = try JSONDecoder().decode(Api1Model.self, from: data)
completion(.success(api1Model))
} catch {
completion(.failure(Api1ServiceError.error))
}
case .failure(let error):
completion(.failure(error))
}
}
}
}
如果感兴趣,这里是结果枚举:
public enum Result<Value> {
case success(Value)
case failure(Error)
}
还有其他几个模型classes,唯一的区别是被解码的实际模型class(在本例中为Api1Model
),以及完成类型别名( Api1Result
)。它在其他几个方法中做完全相同的事情,只是调用 networkClient.getPath()
方法,检查 success/failure,然后调用完成闭包。
想知道是否有任何协议专家可以协助简化和重构,这样我就不会在多个 classes 中使用相同的样板代码?
使用协议扩展(未测试)
protocol ApiModel {
associatedtype ApiType : Decodable = Self
static var path : String { get }
static func getApi1(networkClient: NetworkClient, completion: @escaping (Result<ApiType>) -> Void)
}
extension ApiModel where Self : Decodable {
static func getApi1(networkClient: NetworkClient, completion: @escaping (Result<ApiType>) -> Void) {
networkClient.getPath(path) { result in
switch result {
case .success(let data):
do {
let api1Model = try JSONDecoder().decode(ApiType.self, from: data)
completion(.success(api1Model))
} catch {
completion(.failure(Api1ServiceError.error))
}
case .failure(let error):
completion(.failure(error))
}
}
}
}
让你的所有 类 符合 ApiModel
并添加静态 path
属性。将推断类型别名。
我有多个 class 具有调用公共网络 class 进行 GET api 调用的代码。下面是一个例子:
public typealias Api1Result = (Result<Api1Model>) -> Void
private var path = "the/path/api1"
public enum Api1ServiceError: String, Error {
case error = "Sorry, the api1 service returned something different than expected"
}
extension Api1Model {
public static func getApi1(networkClient: NetworkClient = networkClient, completion: @escaping Api1Result) {
networkClient.getPath(path) { result in
switch result {
case .success(let data):
do {
let api1Model = try JSONDecoder().decode(Api1Model.self, from: data)
completion(.success(api1Model))
} catch {
completion(.failure(Api1ServiceError.error))
}
case .failure(let error):
completion(.failure(error))
}
}
}
}
如果感兴趣,这里是结果枚举:
public enum Result<Value> {
case success(Value)
case failure(Error)
}
还有其他几个模型classes,唯一的区别是被解码的实际模型class(在本例中为Api1Model
),以及完成类型别名( Api1Result
)。它在其他几个方法中做完全相同的事情,只是调用 networkClient.getPath()
方法,检查 success/failure,然后调用完成闭包。
想知道是否有任何协议专家可以协助简化和重构,这样我就不会在多个 classes 中使用相同的样板代码?
使用协议扩展(未测试)
protocol ApiModel {
associatedtype ApiType : Decodable = Self
static var path : String { get }
static func getApi1(networkClient: NetworkClient, completion: @escaping (Result<ApiType>) -> Void)
}
extension ApiModel where Self : Decodable {
static func getApi1(networkClient: NetworkClient, completion: @escaping (Result<ApiType>) -> Void) {
networkClient.getPath(path) { result in
switch result {
case .success(let data):
do {
let api1Model = try JSONDecoder().decode(ApiType.self, from: data)
completion(.success(api1Model))
} catch {
completion(.failure(Api1ServiceError.error))
}
case .failure(let error):
completion(.failure(error))
}
}
}
}
让你的所有 类 符合 ApiModel
并添加静态 path
属性。将推断类型别名。