SwiftAPIClient-SDK
SwiftAPIClient 是一个网络层,能够快速实现服务器 API 调用。
框架通过在设备上存储您的 JSON 数据来包含离线能力,以便按需检索。以下是一些示例。
介绍
该框架的开发是为了加快开发和提高效率。在为简单的数据应用使用 CoreData/Realm 存储离线数据之后,发现需要减少对复杂数据存储的需求,并帮助减小应用程序包的大小。
功能
该项目经过长时间的构建并在许多项目中使用。
- 项目使用了 Swift 的 Codable Protocols,并且所有模型都将符合 Codable。
- 框架有一个机制可以获取用于 DEMO 和测试目的的 JSON 资源文件。
- 有一个存储机制将数据响应存储到 UserDefaults、FileManager 或根本不存储,每个请求都是可配置的。有设置启用 SHA256 编码以确保存储的数据安全。
- 框架中有一个机制可以监控网络状态,如果无连接,则所有调用都将路由到最后收到的调用,如果数据可用,则将其返回,这确保了框架可以离线开箱即用。
- 该框架拥有一个全新的ClosureService,它可以处理调用重复的情况。如果应用在初始调用完成之前多次请求完全相同的调用,框架将停止进一步的调用,但会完成所有代码块。
听起来有很多东西要记住!所以已经设置了简单的辅助函数,它会为你的上述所有操作,这样你就不需要记住了。
支持
- iOS 10.0+ / macOS 10.13+ / tvOS 10.0+ / watchOS 3.0+
要求
- Xcode 11.0+
- Swift 4.2+
安装
CocoaPods
CocoaPods是一个Cocoa项目的依赖管理器。有关使用和安装说明,请访问他们的网站。要使用CocoaPods将SwiftAPIClient集成到你的Xcode项目中,在你的Podfile
中指定它
pod 'SwiftAPIClient'
注意:如果你想仍然使用与Alamofire的旧版本,请锁定你的Pod - 这不再支持
pod 'SwiftAPIClient', '2.1.3'
实现
import SwiftAPIClient
Swift Package Manager
Swift Package Manager 是一个用于自动分发 Swift 代码的工具,并集成到 swift
编译器中。
一旦你设置了你的 Swift 包,将 SwiftAPIClient 作为依赖项添加就像将其添加到 Package.swift
的 dependencies
值一样简单。
dependencies: [
.package(url: "https://github.com/RichAppz/SwiftAPIClient-SDK.git", .upToNextMajor(from: "1.0.3"))
]
客户端
创建所需的网关需要客户端——您可以创建多个以连接到各种服务器和身份验证。
class ClientExample: Service {
// ==========================================
// MARK: Properties
// ==========================================
var rootURL = "<YOUR ENDPOINT>"
var headers: [String: String] = [:]
let networkQueue = OperationQueue()
// ==========================================
// MARK: Singleton
// ==========================================
static let shared = ClientExample()
// ==========================================
// MARK: Initialization
// ==========================================
init() { }
// ==========================================
// MARK: Helpers
// ==========================================
func post(_ request: Request, completion: OperationResponse? = nil) {
makeRequest(.post, request: request, completion: completion)
}
func get(_ request: Request, completion: OperationResponse? = nil) {
makeRequest(.get, request: request, completion: completion)
}
func delete(_ request: Request, completion: OperationResponse? = nil) {
makeRequest(.delete, request: request, completion: completion)
}
func put(_ request: Request, completion: OperationResponse? = nil) {
makeRequest(.put, request: request, completion: completion)
}
func patch(_ request: Request, completion: OperationResponse? = nil) {
makeRequest(.patch, request: request, completion: completion)
}
}
模型示例
CodeModule 已配置,可以帮助解析 JSON 数据。
DateDecodingStrategy - handling various date formats
enum DateType: String {
case iso8601x = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
case iso8601 = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
case java = "yyyy-MM-dd'T'HH:mm:ss.sssZ"
case javaSimple = "yyyy-MM-dd HH:mm:ss Z"
case simple = "yyyy-MM-dd"
static let formats: [DateType] = [iso8601x, iso8601, java, javaSimple, simple]
}
- KeyDecodingStrategy - 处理包含蛇形混合大小写参数的端点,而不需要考虑这些。
使用 Model
泛型类使框架能够存储和检索您的模型。
public struct Movie: Model {
public let title: String?
public let year: Int?
public let rated: String?
public let genre: [String]?
public init?(json: [String: Any]) {
title = json["Title"] as? String
year = json["Year"] as? Int
rated = json["Rated"] as? String
genre = json["Genre"] as? [String]
}
public static var storageIdentifier: String {
return "movie"
}
public static var identifier: String {
return "title"
}
}
端点函数示例
extension Service {
public func fetchMovieWith(query: String, completion: @escaping ((Movie?, Error?) -> Void)) {
get(Request(
parameters: ["t": query])
) { (response) in
let movie: Movie? = try? StorageClient.map(object: response.data)
DispatchQueue.main.async {
completion(movie, response.error)
}
}
}
}
数据检索示例
let account: Account? = try? StorageClient.retrieve()
let accounts: [Account]? = try? StorageClient.retrieve()
附加功能
简写
特性列表相当长,编写请求可能很耗时,所以请尝试使用那些已创建的扩展,允许您这样做
extension Service {
public func fetchMovieWith(query: String, completion: @escaping ((Movie?, Error?) -> Void)) {
stdGetRequest(
RequestModel(
params: ["t": query],
storageType: .fileManager),
completion: completion
)
}
}
如果您想使用 stdGetRequest、stdPostRequest 辅助函数(否则您可以创建自己的手动请求),则完成始终应遵循以下之一
((Model?, Error?) -> Void)?
(([Model]?, Error?) -> Void)?
stdGetRequest
具有多种可为您请求设置的属性(也适用于 POST)
endpoint
- 您设置的枚举值 endpointParam
- 需要放入端点的参数,例如 venues/%@ params
- 需要随请求一起发送的 JSON 主体 storageType
- 您可以在这里指定您想要的存储类型 storageAdditionKey
- 这是您想注入到存储中的额外参数,以识别请求,例如场所的 id 或分页参数,使存储能够识别数据。 notification
- 您设置的 Notification.Name
completion
- 直接传递完成块
所有参数都是可选的或具有默认值,您可以查看代码以了解此信息。
stdGetRequest
和 stdPostRequest
都处理了上述所有功能,应使用手动路由之外的路由。
下载文件
如果您在 Request
中使用 operationType
,将其值设置为 .fileDownload
,然后如果下载了文件,您将得到一个临时文件存储 URL。
get(
Request(
endpoint: "/your-filename.csv",
operationType: .fileDownload,
priority: .high,
qualityOfService: .default)
) { (response) in
DispatchQueue.main.async {
completion(response.fileStoreUrl, response.error)
}
}
上传文件
要上传文件,请使用请求中可用的 FileUpload
模型,并包含一些必需项
public struct FileUpload {
/// If you are converting images you can use `jpegData(compressionQuality: 0.5)`
public let data: Data
/// This is the parameter expected by your server
public let paramName: String
/// Needs to contain the file extension also eg `filename.png`
public let fullFileName: String
/// Standard mimeType string that is expected by HTTP Requests
public let mimeType: String
}
示例
put(
Request(
endpoint: "your-endpoint",
upload: FileUpload(
data: data,
paramName: "file",
fullFileName: "filename.jpg",
mimeType: "image/jpg"
),
priority: .high,
qualityOfService: .default
)
) { (response) in
// Handle response
}
许可(MIT)
版权所有 (c) 2017-2020 RichAppz Limited (https://richappz.com)
特此免费授予任何获得本软件及其相关文档副本(统称“软件”)的人士在不受限制的情况下使用、复制、修改、合并、出版、分发、再许可和/或销售软件副本的权利,并允许该软件提供的人士进行此类操作,但须遵守以下条件
上述版权声明和本许可声明应包含在软件的任何副本或主要部分中。
软件“按原样”提供,不提供任何明示或暗示的保证,包括但不限于适销性、适用于特定用途和侵权保证。在任何情况下,作者或版权所有者均不对任何索赔、损害或其他责任承担责任,无论是在合同行动、侵权或其他情况下,无论是在与软件或与使用或其它软件处置有关的软件之中。
Rich Mucha, RichAppz Limited [email protected]