Y—Network
一个用于 iOS 和 tvOS 的网络层。

🤖 在寻找 Android 版本吗?请查看这里

文档

文档由源代码注释自动生成,并作为静态网站托管在 GitHub Pages 上:https://yml-org.github.io/ynetwork-ios/

用法

NetworkManager

你需要在你的 AppDelegate、SceneDelegate 或其他顶层应用协调器中实例化一个 NetworkManager。 然后,你应该使用依赖注入将其传递给需要它的各种服务层或视图模型。

NetworkManager 可以通过 NetworkManagerConfiguration 对象和/或通过子类化进行广泛配置,但对于基本功能,两者都不是必需的。

// Declare an instance of the network manager, so that it can be injected where needed.
private let networkManager = NetworkManager()

NetworkRequest

你发出的每个网络请求都将是符合 NetworkRequest 协议的独立对象(类或结构体)。 此协议允许你配置有关请求的许多内容(路径、方法、查询参数、主体、超时、标头等),但它具有合理的默认值,因此唯一必需的属性是 path(要访问的端点)。

struct GetUsersRequest { }

extension GetUsersRequest: NetworkRequest {
    // which endpoint to hit
    var path: PathRepresentable { "https://myendpoint.com/api/v1/users" }
}

然后你可以像这样发出请求(请求将返回一个 User 对象数组或抛出一个 Error)。 以下示例展示了如何使用现代 async / await 方法,但也存在基于完成处理程序的 submit 重载。

func fetchUsers() async {
    let request = GetUsersRequest()

    do {
        let users = try await networkManager.submit(request)
        // handle success
    } catch {
        // handle failure
    }
}

使用相对路径

NetworkRequest 通过同时拥有 basePathpath 属性来支持相对路径。 当 basePath 为 nil(默认值)时,path 被视为绝对路径,否则,当 basePath 已指定时,它被视为相对路径。 我们建议使用 enum 来列出应用程序的基本路径和路径。

enum MyApiBasePath: String, PathRepresentable {
    case prod = "https://myendpoint.com/api/v1"

    // In a real app you'd probably have additional development endpoints
    // such as dev, qa, uat, sandbox, etc.
}

extension MyApiBasePath {
    // convenience property to point to the current environment
    static var current: MyApiBasePath = .prod
}

enum MyApiEndpoints: String, PathRepresentable {
    case users
}

然后,你可以为你的应用支持的每个不同的 api 服务器声明一个新的请求协议。

// You can declare a new protocol for each major endpoint your app supports
protocol MyApiRequest: NetworkRequest { }

extension MyApiRequest {
    // All requests sharing the same base path
    var basePath: PathRepresentable? { MyApiBasePath.current }
}

然后,每个请求都可以从特定于其 api 服务器的协议派生。

struct GetUsersRequest { }

extension GetUsersRequest: MyApiRequest {
    // which endpoint to hit
    var path: PathRepresentable { MyApiEndpoints.users }
}

在路径中使用关联值

大多数 api 的某些请求的路径都包含一个唯一标识符。 将关联值添加到你的 endpoints enum 是处理这些情况的好方法。 这需要在我们的 endpoint enum 的声明方式上进行一些重新配置。

enum MyApiEndpoints {
    case users
    case user(id: String)
}

extension MockApiEndpoints: PathRepresentable {
    var pathValue: String {
        switch self {
        case .users:
            return "users"
        case .user(let id):
            return "users/\(id)"
        }
    }
}

然后,你可以像这样声明一个针对特定用户的请求

struct GetUserRequest {
    /// Id of the user to fetch
    let userId: String
}

extension GetUserRequest: MyApiRequest {
    // which endpoint to hit
    var path: PathRepresentable { MyApiEndpoints.user(id: userId) }
}

安装

你可以通过将其作为包依赖项添加到 Xcode 项目中来添加 Y-Network。

  1. File菜单中,选择Add Packages...
  2. 在包仓库 URL 文本字段中输入“https://github.com/yml-org/ynetwork-ios
  3. 单击Add Package

为 Y-Network 做出贡献

要求

SwiftLint (linter)

brew install swiftlint

Jazzy (documentation)

sudo gem install jazzy

设置

克隆存储库并在 Xcode 中打开 Package.swift

版本控制策略

我们使用语义版本控制

{major}.{minor}.{patch}

例如。

1.0.5

分支策略

我们为我们的框架使用简化的分支策略。

分支命名约定

feature/{ticket-number}-{short-description}
bugfix/{ticket-number}-{short-description}

例如。

feature/CM-44-button
bugfix/CM-236-textview-color

Pull Requests

在提交 pull request 之前,你应该

  1. 编译并确保没有警告和错误。
  2. 运行所有单元测试并确认一切通过。
  3. 检查单元测试覆盖率并确认所有新/修改的代码都被完全覆盖。
  4. 从命令行运行 swiftlint 并确认没有违规行为。
  5. 从命令行运行 jazzy 并确认你具有 100% 的文档覆盖率。
  6. 考虑使用 git rebase -i HEAD~{commit-count} 将你的最后 {commit-count} 个提交合并成功能块。
  7. 如果父分支(通常是 main)的 HEAD 自你创建分支以来已更新,请使用 git rebase main 来 rebase 你的分支。
    • 永远不要将父分支合并到你的分支中。
    • 始终基于父分支 rebase 你的分支。

在提交 pull request 时

在合并 pull request 时

发布新版本

生成文档(通过 Jazzy)

你可以使用 Terminal 中的以下命令直接从源代码生成自己的本地文档集

jazzy

这将在 /docs 下生成一组文档。 默认配置在默认配置文件 .jazzy.yaml 文件中设置。

要查看其他文档选项,请输入

jazzy --help

每次提交推送到 main 时,GitHub Action 都会自动运行,该 Action 运行 Jazzy 为我们的 GitHub 页面生成文档:https://yml-org.github.io/ynetwork-ios/