hyperspace 5.1.0

Hyperspace 5.1.0

Tyler MilnerTyler MilnerWill McGintyEarl GaspardRyan Gant 维护。



  • Tyler Milner

hyperspace

CI Status Version Carthage compatible SwiftPM compatible Platform codecov License

hyperspace 在 URLSession 和 HTTP 之上提供了一个简单的抽象。有几个主要目标

  • 保持简单。
  • 将库的整体大小保持在最小。当然,可能会有些样板代码(如 HTTP 定义),但我们的主要目标是保持库高度功能化和可维护,而不过度设计。
  • 针对我们遇到的最常见的网络使用案例定制库。我们将继续根据所有我们构建的应用程序中的共同需求添加功能。

内容

  • HTTP - 包含标准 HTTP 定义和类型。如果您觉得这里缺少某些内容,请提交 pull request。
  • Request - 一个定义网络请求细节的结构,包括期望的结果和错误类型。这基本上是 URLRequest 的一个薄 wrapper,利用了 HTTP 中的定义。
  • TransportService - 使用 TransportSession(默认为 URLSession)执行 URLRequests。处理原始 HTTPData
  • BackendService - 使用 TransportService 执行 Requests。将 TransportService 返回的原始 Data 转换为由 Request 定义的反应模型类型。这是您的应用将直接处理的 main worker 对象

使用说明

1. 创建请求

创建请求时,您有多种选择。这些包括创建静态函数,以减少创建 Request 对象时的冗余,或者简单地本地创建。此外,如果您的网络请求比较复杂,您还可以创建自己的自定义结构体,将其封装并处理 Request 对象。

选项 1 - 扩展 Request

以下示例说明了如何创建一个 Request 的扩展,这可以显著减少创建类似在社交网络动态中创建新帖子时的请求的冗余。它利用了 Request 中的许多默认值(所有这些都是可定制的),以保持定义简洁。

extension Request where Response == Post {
    
    static func createPost(_ post: NewPost) -> Request<Post> {
        return Request(method: .post, url: URL(string: "https://jsonplaceholder.typicode.com/posts")!, headers: [.contentType: .applicationJSON], body: try? HTTP.Body.json(post))
    }
}

选项 2 - 在本地定义每个 Request

let createPostRequest: Request<Post> = Request(method: .post, url: URL(string: "https://jsonplaceholder.typicode.com/posts")!, headers: [.contentType: .applicationJSON], body: try? HTTP.Body.json(post))

选项 3 - 创建一个包装 RequestCREATEPOSTREQUEST

struct CreatePostRequest {
    let newPost: NewPost
    
    var request: Request<Post> {
        return Request(method: .post, url: URL(string: "https://jsonplaceholder.typicode.com/posts")!, headers: [.contentType: .applicationJSON], body: try? HTTP.Body.json(post))
    }
}

对于上面的示例,Post 响应类型和 NewPost 身体定义如下

struct Post: Decodable {
    let id: Int
    let userId: Int
    let title: String
    let body: String
}
struct NewPost: Encodable {
    let userId: Int
    let title: String
    let body: String
}

2. 创建请求默认值(可选)

为了避免在您的应用程序中为每个请求定义默认的 Request 属性值,利用 Hyperspace 提供的 RequestDefaults 可能很有用。甚至可以自定义这些

RequestDefaults.defaultCachePolicy = .reloadIgnoringLocalCacheData // Default cache policy is '.useProtocolCachePolicy'
RequestDefaults.defaultDecoder = MyCustomDecoder() // Default decoder is JSONDecoder()

3. 创建一个 BackendService 来执行您的请求

我们建议通过为与您的 API 每个部分进行通信的每个部分创建单独的“控制器”对象来遵守接口隔离原则。每个控制器应公开一组相关的函数,并使用 BackendService 来执行请求数据,然而,在这个简单的例子中,我们将直接在视图控制器上作为 private 属性使用 BackendService

class ViewController: UIViewController {
    private let backendService = BackendService()

    // Rest of your view controller code...
}

4. 实例化您的请求

假设一个视图控制器应该在用户点击“发送”按钮时创建帖子。下面是一个可能的实现

@IBAction private func sendButtonTapped(_ sender: UIButton) {
    let title = ... // Get the title from a text view in the UI...
    let message = ... // Get the message from a text view/field in the UI...
    let post = NewPost(userId: 1, title: title, body: message)

    let createPostRequest = CreatePostRequest(newPost: post)

    // Execute the network request...
}

5. 使用 BackendService 执行请求

对于上面的示例,以下是执行请求和解析响应的方法。尽管所有数据转换都发生在底层 URLSession 所使用的后台队列上,但是所有 BackendService 完成回调发生在主队列上,因此你无需担心在更新 UI 之前线程问题。注意,以下成功响应关联值的类型是与上面定义的 CreatePostRequest 中的 Post 结构。

do {
    let post = NewPost(userId: 1, title: title, body: "")
    let createPostRequest = Request<Post>.createPost(post)
    let createdPost = try await backendService.execute(request: createPostRequest)
    // Insert the new post into the UI...
    
} catch {
    // Alert the user to the error...
}

示例

克隆仓库

git clone https://github.com/BottleRocketStudios/iOS-Hyperspace.git

从这里,您可以打开 Hyperspace.xcworkspace 并运行示例

共享代码

  • Models.swift, Requests.swift
    • 示例间共享的模型和网络上请求。

示例目标

  • Hyperspace-iOSExample
    • ViewController.swift
      • 查看如何在您的 iOS 应用中使用此示例。
  • Hyperspace-tvOSExample
    • ViewController.swift
      • 查看如何在您的 tvOS 应用中使用此示例(这实际上与 iOS 示例相同)。
  • Hyperspace-watchOSExample 扩展
    • InterfaceController.swift
      • 查看您如何在您的watchOS应用中使用此代码的一个简化示例。

Playgrounds

  • Playground/Hyperspace.playground
    • 查看并运行一个定义模型、网络请求并在执行请求时类似上述示例目标的单个文件。
  • Playground/Hyperspace_DELETE.playground
    • 如何处理不返回结果的请求的示例。这通常在DELETE请求中很常见。

系统要求

  • iOS 13.0+
  • tvOS 13.0+
  • watchOS 6.0+
  • macOS 11+
  • Swift 5.6

安装

Cocoapods

Hyperspace通过CocoaPods提供。要安装它,只需在Podfile中添加以下行:

pod 'Hyperspace'

Carthage

将以下内容添加到您的Cartfile

github "BottleRocketStudios/iOS-Hyperspace"

运行carthage update,并按照Carthage的README中描述的步骤进行。

Swift 包管理器

dependencies: [
    .package(url: "https://github.com/BottleRocketStudios/iOS-Hyperspace.git", from: "5.0.0")
]

作者

Bottle Rocket Studios

许可证

Hyperspace是在Apache 2.0许可证下可用的。有关更多信息,请参阅LICENSE.txt文件。

贡献

请参阅CONTRIBUTING文档。感谢贡献者!