JNetworkingKit
此项目包含Swift的通用网络设置,但也可以通过网关从Objective-C调用。
本提案中的关键字包括
- 只有一个类执行请求
- 只有一个类解析请求
- 只有一个类验证请求
RequestExecutor
可以轻松扩展RequestClient
可以轻松扩展RequestParser
可以轻松扩展RequestValidator
可以轻松扩展
本提案是以以下原则为基础构建的
- 面向协议编程
- SOLID的职责分离
它们共同使代码具有完全的可测试性,并且可以以测试驱动的方式开发和扩展。
架构
架构有8个不同的实体,它们在应用级别(您的应用程序)或库级别(自身库)定义。
应用级别
环境
:应包含关于当前环境的信息,它是库环境结构的扩展,包含环境,以便使用点符号访问它们。
extension Environment {
static let develop = Environment(server: "http://192.168.0.1",
path: "test",
version: "v1")
static let production = Environment(server: "http://www.<YOUR-WEBSITE>.com")
}
网关
:网络层的入口点,一个定义执行网络调用的相关方法的唯一类。在示例应用程序中,我们创建了一个空的网关
类,该类可以从 Objective-C 中使用,并将被任何请求集扩展。如果您的应用程序有两个服务集(产品 和 用户),则可以创建 2 个 Gateway 的扩展。
protocol ProductsGateway {
func getProducts(onSuccess: @escaping (Product) -> Void, onError: @escaping (Error) -> Void)
func getProduct(with id: String, onSuccess: @escaping (Product) -> Void, onError: @escaping (Error) -> Void)
}
extension Gateway: ProductsGateway {
@objc func getProducts(onSuccess: @escaping (Product) -> Void, onError: @escaping (Error) -> Void) {
// ...
}
@objc func getProduct(with id: String, onSuccess: @escaping (Product) -> Void, onError: @escaping (Error) -> Void) {
// ...
}
}
protocol UserGateway {
func getUser(with id: String, onSuccess: @escaping (User) -> Void, onError: @escaping (Error) -> Void)
}
extension Gateway: UserGateway {
@objc func getUser(with id: String, onSuccess: @escaping (User) -> Void, onError: @escaping (Error) -> Void) {
// ...
}
}
请求
:包含执行网络调用所需的所有必要信息。一个请求
是环境
和路由
的结果。
库级别
请求操作
:负责提供和管理请求
、执行器
和解析器
的正确实例。请求执行器
:负责使用正确的客户端
执行请求。Executor 的扩展版本可用于添加更多业务逻辑,如缓存或观察者模式。请求客户端
:负责执行请求。默认的客户端
使用URLSession
组件,但可以创建不同的客户端
以使用不同的系统或库(如 Alamofire)。请求验证器
:负责执行请求的验证。默认实现检查响应代码,但也可以验证头或体。请求解析器
:负责解析响应并创建最终对象。
该库以 请求操作
为中心。它使用 Swift 的泛型 定义其变量,因此开发人员可以实例化和使用不同的 请求执行器
、请求客户端
和 请求解析器
实例,以向网络层添加更多功能和能力。
数据流
使用此方案的常用流程为
- 为相关服务集创建
网关
的扩展。在示例应用程序中,我们创建了 MOvieGateway 协议。如果已存在相关扩展,为要使用的服务添加适当的方法
protocol MovieGateway {
func getMovie(onSuccess: @escaping (Movie) -> Void, onError: @escaping (Error) -> Void)
}
extension Gateway: MovieGateway {
@objc func getMovie(onSuccess: @escaping (Movie) -> Void, onError: @escaping (Error) -> Void) {
MovieDetailRequestOperation().execute(onSuccess: onSuccess, onError: onError)
}
}
- 定义适当的
路由器
,该路由器定义不同服务的相关路由
。我们建议按 点表示法 定义它们。
struct MovieRouter {
static var list: RequestRoute {
let path = "?apikey={apikey}&t={t}"
let parameters = ["apikey": "<YOUR-OMDB-KEY>", "t": "Matrix"]
return RequestRoute(path: path, parameters: parameters)
}
}
- 为需要使用的服务创建新的
请求操作
。新操作将定义正确的解析器、执行器和请求
class MovieDetailRequestOperation: NSObject, RequestOperationType {
typealias Result = Movie
var executor = RequestExecutor()
var parser = MovieDetailRequestParser()
var validator = RequestValidator()
var request = Request(route: MovieRouter.list)
}
-
在
网关
上调用适当的方法- 在
onSuccess
完成块中按需要处理数据 - 在
onError
完成块中按需要处理错误
- 在
[self.gateway getMovieOnSuccess:^(Movie *movie) {
NSLog(@"Fetched movie %@", movie.title);
} onError:^(NSError *error) {
NSLog(@"Error fetching the movie: %@", error.localizedDescription);
}];
注释
支持Objective-C
所有的魔法现在都是,并将继续是使用Swift编写的。我们不希望在库的创建中限制自己,这就是为什么Objective-C唯一需要与能够交互的是在应用层面上创建的网关
。
Try/Catch & 错误处理
你可能已经注意到其中有很多try
和throw
关键字。正确和完整的错误处理将会是一个挑战,并且代码库中将有do {} catch {}
闭包。
目前,请求网关可能会生成一个Error
,我们可以在onError
完成块中处理它。
请求执行器
你可能注意到,目前RequestExecutor
只是位于RequestOperation
和选择的RequestClient
之间的代理,这为我们提供了将业务逻辑添加到网络层以及根据我们的需求更改客户端的自由。
一个简单的例子是CacheRequestExecutor
:它增加一个非常简单的缓存系统来展示如何轻松扩展它。这也是实现Observable
模式的好点。
请求解析器
解析器可以通过仅更改一行代码扩展或更改以满足我们的需求,只需在RequestOperation
中使用不同的解析器即可。为了展示其简单性,项目已添加了一个HeaderRequestParser
,它可以解析响应头而不是响应参数。
安装
库
$ git clone https://github.com/jumbo-tech-campus/JNetworkingKit
$ cd JNetworkingKit/JNetworkingKit
$ open JNetworkingKit.xcworkspace
现在您可以打开工作区并运行单元测试,以确保一切正常工作。
示例应用
$ git clone https://github.com/jumbo-tech-campus/JNetworkingKit
$ cd JNetworkingKit/DemoApp
$ open DemoApp.xcworkspace
打开工作区后,请在 MovieRouter.swift
文件中替换 API密钥。在 OMDb Api 上可以创建新的密钥。
现在您可以运行示例应用程序。共有2个屏幕
- 第一个将加载图片并在屏幕上显示
- 第二个将下载关于《黑客帝国》的电影信息,并在屏幕上显示标题和剧情
未来改进
- 创建一个
Logger
,可以在调试模式下记录信息。 - 在
Request
上添加对+
运算符的支持,以实现父子概念 - 添加Cocoapod支持
- 添加Carthage支持
- 添加Swift Package Manager支持