ws 5.1.3

ws 5.1.3

测试已测试
Lang语言 SwiftSwift
许可证 MIT
发布最后发布2020年6月
SPM支持SPM

s4cha维护。



 
依赖项
Arrow~> 5.1.1
thenPromise~> 5.1.2
Alamofire~> 4.9.1
 

ws 5.1.3

ws

重要通知:再见ws... 欢迎Networking !

Networking 是ws项目的下一代。把它看作是为iOS13编写的ws 2.0。它使用Combine原生Apple的框架,并通过Then Promise库替换Arrow依赖项,以支持Codable(Arrow仍然可以很容易地进行适配)并替换Alamofire依赖项,以使用更简单的纯本地URLSession实现。本质上,更少的依赖项,更多的原生功能,API几乎相同。如果您的应用支持iOS13及以上,强烈建议迁移到Networking。由于向后兼容的原因,WS将“维护”但不建议从iOS13开始使用。

ws

Language: Swift 5 Platform: iOS 8+ Carthage compatible Cocoapods compatible License: MIT Build Status codebeat badge Release version

原因 - 示例 - 安装

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)" }
}

然后我们可以实现一个获取 RestResourceget 版本

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 函数(如 postputdelete 等)!🎉

安装

Swift 包管理器 (SPM)

由于同时支持所有包管理器的挑战,SPM 支持可在单独的分支 spm-only 上使用。

Carthage

在你的Cartfile中

github "freshOS/ws"
  • 运行 carthage update
  • ws.frameworkCarthage/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 上,并带来您网站的链接:)