NetworkingX
简介
NetworkingX 是一个建立在 swift
语言 URLSession
基础上的干净、轻量级框架,用于制作 HTTP 请求。该框架的主要目标是分离更小的网络协议步骤,给我们代码管理带来额外的灵活性。
要求
- iOS 10.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+
- Xcode 11+
- Swift 5.1+
安装
CocoaPods
CocoaPods 是 Cocoa 项目的依赖管理器。要安装 NetworkingX,只需将以下行添加到您的 Podfile
文件中。
pod 'NetworkingX'
Swift Package Manager
Swift Package Manager 是一个自动分布 Swift 代码的工具,并且已集成到 swift
编译器中。NetworkingX 也支持在各种受支持的平台上使用它。
一旦您已经设置了 Swift 包,将 NetworkingX 添加为依赖项就像将其添加到 Package.swift
的 dependencies
值一样简单。
dependencies: [
.package(url: "https://github.com/prashantLalShrestha/NetworkingX.git", .upToNextMajor(from: "1.3.0"))
]
用法
NetworkingX 非常容易使用。但是,有一些协议和类需要注意。
NetworkConfigurable
这是一个用于配置基本 HTTP 网络配置的协议。这包括托管地址的基本 URL、公共头和公共查询参数。
public protocol NetworkConfigurable {
var baseURL: URL { get }
var headers: [String: String] { get }
var queryParameters: [String: String] { get }
}
我们可以从其默认实现 ApiDataNetworkConfig
中创建一个对象。
let config = ApiDataNetworkConfig(baseURL: URL(string: "https://url.to.api/"))
NetworkService
这是一个用于发送 HTTP 请求的服务协议。其默认实现 DefaultNetworkService
包装了 URLSession().dataTask
函数。您可以使用此协议创建自己的实现,例如使用 Alamofire
。
public protocol NetworkService {
typealias CompletionHandler = (Result<Data?, NetworkError>) -> Void
func request(endpoint: Requestable, completion: @escaping CompletionHandler) -> NetworkCallable?
}
上面创建的该网络 config
对象用于 NetworkService。我们可以创建一个 NetworkService 对象:
let networkService = DefaultNetworkService(config: config)
NetworkSessionManager
NetworkSessionManager 在 HTTP 请求之间作为拦截器工作。我们可以使用此协议来维护访问令牌、身份验证。
public protocol NetworkSessionManager {
var acceptableStatusCodes: [Int] { get }
typealias CompletionHandler = (Data?, URLResponse?, Error?) -> Void
func request(_ request: URLRequest,
completion: @escaping CompletionHandler) -> NetworkCallable
}
通常,我们在 NetworkService
类中使用 NetworkSessionManager
。
let networkService = DefaultNetworkService(config: config, sessionManager: DefaultNetworkSessionManager())
端点
我们为每次网络API调用创建一个端点。 Endpoint
实现了 Requestable
协议。
public protocol Requestable {
var path: String { get }
var isFullPath: Bool { get }
var method: HTTPMethodType { get }
var headerParamaters: [String: String] { get }
var queryParametersEncodable: Encodable? { get }
var queryParameters: [String: Any] { get }
var bodyParamatersEncodable: Encodable? { get }
var bodyParamaters: [String: Any] { get }
var bodyEncoding: ParameterEncoding { get }
func urlRequest(with networkConfig: NetworkConfigurable) throws -> URLRequest
}
如您在上面协议中看到的,我们将在这里定义我们的API调用配置。
struct Endpoints {
static func authenticateUser(request: UserAuthenticationRequest) -> Endpoint<UserAuthenticationResponse> {
return Endpoint(path: "path/of/login",
method: .post,
bodyParamatersEncodable: request,
bodyEncoding: URLEncoding.default
)
}
}
ParameterEncoding
一种类型,用于定义如何将一组参数应用到 URLRequest
。框架中内置了某些 ParameterEncoding 实现。
- URLEncoding
- JSONEncoding
- XMLEncoding
- MultiPartEncoding
然而,您可以使用此协议创建自己的 Encoding 实现,然后在 Endpoint
中使用它。
DataTransferService
DataTransferService 是用于帮助 Endpoint
、NetworkService
和 ErrorResolver
完成大部分工作的地方。
public protocol DataTransferService {
typealias CompletionHandler<T> = (Result<T, DataTransferError>) -> Void
@discardableResult
func request<T: Decodable, E: ResponseRequestable>(with endpoint: E,
completion: @escaping CompletionHandler<T>) -> NetworkCallable? where E.Response == T
@discardableResult
func request<E: ResponseRequestable>(with endpoint: E,
completion: @escaping CompletionHandler<Void>) -> NetworkCallable? where E.Response == Void
}
为了简单起见,您可以使用默认实现 DefaultDataTransferService
作为
let dataTransferService = DefaultDataTransferService(with: networkService)
DataTransferErrorResolver
它用于将 NetworkError
解析为 DataTransferError
。我们可以为该协议创建一个实现类来映射我们的错误。
public protocol DataTransferErrorResolver {
func resolve(error: NetworkError) -> Error
}
然后,在 DefaultDataTransferService
中使用它作为
let dataTransferService = DefaultDataTransferService(with: networkService,
errorResolver: DefaultDataTransferErrorResolver())
现在是最甜的部分,
完成我们的NetworkConfig
、NetworkSessionManager
、NetworkService
、Endpoint
、DataTransferService
设置后,我们现在可以发起网络请求了。
let request = UserAuthenticationRequest(userName: "username", loginPassword: "password")
let endpoint = Endpoints.authenticateUser(request: request)
let task = dataTransferService.request(with: endpoint) { result in
switch result {
case .success(let response):
// TODO: Update UI
case .failure(let error):
// TODO: Handle Errors in UI
}
}
task?.resume()
本框架的主要目标是将网络协议分步骤进行分离,这样我们可以更灵活地在代码管理中实现,尤其是在清晰的架构
中。