⚠ 重要通知:再见ws... 欢迎Networking !
Networking 是ws项目的下一代。把它看作是为iOS13编写的ws 2.0。它使用Combine原生Apple的框架,并通过
ws
let ws = WS("http://jsonplaceholder.typicode.com")
ws.get("/users").then { json in
// Get back some json \o/
}
因为99%的iOS应用中使用了JSON API,因此这应该是简单的。
我们开发者应该关注应用逻辑而不是样板代码。
更少的代码是更好的代码。
试试吧!
ws 是 freshOS iOS 工具集的一部分。在示例 App 中尝试一下吧!下载 Starter Project
如何
通过提供一个轻量级客户端来自动生成每个人都必须编写的样板代码。
通过提供一个简单易懂的API,简单、清晰地完成任务。
从JSON API中快速获取模型已经成为了过去的问题。
什么是
- 构建简洁的API
- 自动映射您的模型
- 内置网络日志记录器
- 站在巨人的肩膀上(Alamofire & Promises)
- 纯Swift,简单且轻量级
使用说明
裸JSON
import ws // Import ws at the top of your file
import Arrow // Import Arrow to get access to the JSON type
class ViewController: UIViewController {
// Set webservice base URL
let ws = WS("http://jsonplaceholder.typicode.com")
override func viewDidLoad() {
super.viewDidLoad()
// Get back some json instantly \o/
ws.get("/users").then { (json:JSON) in
print(json)
}
}
}
设模解析设置
创建一个 User+JSON.swift
文件并将 JSON 键映射到你的模型属性
import Arrow
extension User: ArrowParsable {
mutating func deserialize(_ json: JSON) {
identifier <-- json["id"]
username <-- json["username"]
email <-- json["email"]
}
}
注意:ws
使用 Arrow
进行 JSON 解析 https://github.com/freshOS/Arrow
选择您想返回的内容
在这里,您将要创建一个封装您请求的功能。根据您想返回的内容,编写该函数的方式有很多种。一个空块,JSON,模型或模型的数组。
func voidCall() -> Promise<Void> {
return ws.get("/users")
}
func jsonCall() -> Promise<JSON> {
return ws.get("/users")
}
func singleModelCall() -> Promise<User> {
return ws.get("/users/3")
}
func modelArrayCall() -> Promise<[User]> {
return ws.get("/users")
}
正如您所能注意到的,仅通过更改返回类型,ws 自动就知道该做什么,比如,尝试将响应解析为User
模型。
这使我们能够保持简洁,无需编写额外的代码。 \o/
注意:ws
使用then
处理Promise https://github.com/freshOS/then
获取它!
voidCall().then {
print("done")
}
jsonCall().then { json in
print(json)
}
singleModelCall().then { user in
print(user) // Strongly typed User \o/
}
modelArrayCall().then { users in
print(users) // Strongly typed [User] \o/
}
设置
想要记录所有网络调用和响应吗?
ws.logLevels = .debug
想要隐藏网络活动指示器吗?
ws.showsNetworkActivityIndicator = false
想要覆盖默认会话管理器来定制信任策略吗?
import Alamofire
ws.sessionManager = SessionManager(serverTrustPolicyManager: ServerTrustPolicyManager(
policies: ["myspecialhostname.com" : .disableEvaluation]
))
API 示例
以下是文章的典型 CRUD 示例
extension Article {
static func list() -> Promise<[Article]> {
return ws.get("/articles")
}
func save() -> Promise<Article> {
return ws.post("/articles", params: ["name":name])
}
func fetch() -> Promise<Article> {
return ws.get("/articles/\(id)")
}
func update() -> Promise<Void> {
return ws.put("/articles/\(id)", params: ["name":name])
}
func delete() -> Promise<Void> {
return ws.delete("/articles/\(id)")
}
}
以下是我们在代码中如何使用它的示例
// List Articles
Article.list().then { articles in
}
// Create Article
var newArticle = Article(name:"Cool story")
newArticle.save().then { createdArticle in
}
// Fetch Article
var existingArticle = Article(id:42)
existingArticle.fetch().then { fetchedArticle in
}
// Edit Article
existingArticle.name = "My new name"
existingArticle.update().then {
}
// Delete Article
existingArticle.delete().then {
}
HTTP 状态码
当一个请求失败时,我们通常想通过 HTTP 状态码来了解失败的原因。以下是获取它的方法
ws.get("/users").then {
// Do something
}.onError { e in
if let wsError = e as? WSError {
print(wsError.status)
print(wsError.status.rawValue) // RawValue for Int status
}
}
您可以在此处找到完整的 WSError
枚举 -> https://github.com/freshOS/ws/blob/master/ws/WSError.swift
奖励 - 加载更多模式
我们经常遇到处理列表和加载更多项目的能力。在这里,我们将看到一个使用 ws
实现此模式的示例。这不包括在内,因为逻辑本身取决于你的后端实现。这将为你的自定义版本提供一个示例。
实现
import ws
import then
import Arrow
class LoadMoreRequest<T:ArrowParsable> {
var limit = 12
private var params = [String:Any]()
private var offset = 0
private var call: WSRequest!
private var canLoadMore = true
private var aCallback:((_ ts: [T]) -> [T])? = nil
init(_ aCall: WSRequest) {
call = aCall
}
func resetOffset() {
offset = 0
canLoadMore = true
}
func hasMoreItemsToload() -> Bool {
return canLoadMore
}
func fetchNext() -> Promise<[T]> {
params = call.params
params["limit"] = limit
params["offset"] = offset
call.params = params
offset += limit
return call.fetch()
.registerThen(parseModels)
.resolveOnMainThread()
}
private func parseModels(_ json: JSON) -> [T] {
let mapper = WSModelJSONParser<T>()
let models = mapper.toModels(json)
if models.count < limit {
canLoadMore = false
}
return models
}
}
正如你所见,我们有一个强类型请求。
限制是可调整的。
它封装了WSRequest。
它处理偏移逻辑以及是否还有更多项目可加载。
这就是我们需要的全部!
现在,这就是我们如何构建LoadMoreRequest
func loadMoreUsersRequest() -> LoadMoreRequest<User> {
return LoadMoreRequest(ws.getRequest("/users"))
}
使用方法
以下是我们在控制器中使用它的方式
class ViewController: UIViewController {
// Get a request
let request = api.loadMoreUsersRequest()
override func viewDidLoad() {
super.viewDidLoad()
request.limit = 5 // Set a limit if needed
}
func refresh() {
// Resets the request, usually plugged with
// the pull to refresh feature of a tableview
request.resetOffset()
}
func loadMore() {
// Get the next round of users
request.fetchNext().then { users in
print(users)
}
}
func shouldDisplayLoadMoreSpinner() -> Bool {
// This asks the requests if there are more items to come
// This is useful to know if we show the "load more" spinner
return request.hasMoreItemsToload()
}
}
看这里,现在你有一个简单的方法来处理你的App中的加载更多请求
附加功能 - 简化RESTful路由使用
当与一个 RESTFUL
API 一起工作时,我们可以有所娱乐,并且可以更进一步。
通过引入一个 RestResource
协议
public protocol RestResource {
static func restName() -> String
func restId() -> String
}
我们可以有一个构建我们的 REST
URL 的函数
public func restURL<T:RestResource>(_ r:T) -> String {
return "/\(T.restName())/\(r.restId())"
}
我们将 User
模型符合该协议
extension User:RestResource {
static func restName() -> String { return "users" }
func restId() -> String { return "\(identifier)" }
}
然后我们可以实现一个获取 RestResource
的 get
版本
public func get<T:ArrowParsable & RestResource>(_ restResource:T, params:[String:Any] = [String:Any]()) -> Promise<T> {
return get(restURL(restResource), params: params)
}
然后
ws.get("/users/\(user.identifier)")
可以写成这个样子
ws.get(user)
当然,同样的逻辑也可以应用于所有其他 ws 函数(如 post
、put
、delete
等)!
安装
Swift 包管理器 (SPM)
由于同时支持所有包管理器的挑战,SPM 支持可在单独的分支 spm-only
上使用。
Carthage
在你的Cartfile中
github "freshOS/ws"
- 运行
carthage update
- 将
ws.framework
从Carthage/Build/iOS
拖至 “链接框架和库”(“常规”设置选项卡) - 转到
项目
>目标
>构建阶段
+新运行脚本阶段
/usr/local/bin/carthage copy-frameworks
添加输入文件
$(SRCROOT)/Carthage/Build/iOS/ws.framework
$(SRCROOT)/Carthage/Build/iOS/Alamofire.framework
$(SRCROOT)/Carthage/Build/iOS/Arrow.framework
$(SRCROOT)/Carthage/Build/iOS/then.framework
此操作链接了ws及其依赖项。
手动操作
Carthage 非常有用,因为它处理了拉取依赖项的工作,比如 Arrow、then 和 Alamofire。棒的地方在于它真的很透明。我的意思是,你只需要用 Carthage 在旁边拉取和构建依赖项,然后手动将框架链接到你的 Xcode 项目中。
没有 Carthage,我会看到两个解决方案:1 - 复制粘贴所有源代码:ws / then / Arrow / Alamofire,听起来不是很有趣;2 - 通过在各个存储库中获取 .frameworks 手动链接框架(ws + 依赖),或者使用 Carthage 构建它们。
Cocoapods
target 'MyApp'
pod 'ws'
use_frameworks!
Swift 版本
Swift 2 -> 版本 1.3.0
Swift 3 -> 版本 2.0.4
Swift 4 -> 版本 3.0.0
Swift 4.1 -> 版本 3.1.0
Swift 4.2 -> 版本 3.2.0
Swift 5.0 -> 版本 5.0.0
Swift 5.1 -> 版本 5.1.0
Swift 5.1.3 -> 版本 5.1.1
赞助者
喜欢这个项目吗?提供咖啡或通过每月捐赠支持我们,帮助我们继续活动:)
赞助商
成为赞助商,将您的标志放在 Github 的 README 上,并带来您网站的链接:)