Swift合并复杂API请求

vngu2lb8  于 2022-10-31  发布在  Swift
关注(0)|答案(1)|浏览(207)

我刚开始学习合并,因此我不知道如何向API发出复杂的请求。
有必要创建一个应用程序,用户可以在其中的输入字段中输入公司的GitHub帐户的名称,并获得一个开放的仓库及其分支的列表。
有两种API方法:

  1. https://api.github.com/orgs/<ORG_NAME>/repos此方法按名称返回组织帐户存储库的列表。例如,您可以尝试请求Apple的存储库列表https://api.github.com/orgs/apple/repos
    此方法的结构
struct Repository: Decodable {

 let name: String

 let language: String?

    enum Seeds {
        public static let empty = Repository(name: "", language: "")
    }

}
  1. https://api.github.com/repos/<ORG_NAME>/<REPO_NAME>/branches此方法用于获取指定仓库中的分支名称。
    此方法的结构
struct Branch: Decodable {

 let name: String

}

因此,我需要得到一个这样的结构的数组。

struct BranchSectionModel {
    var name: Repository
    var branchs: [Branch]
}

为此我有两个职能:

func loadRepositorys(orgName: String) -> AnyPublisher<[Repository], Never> {

        guard let url = URL(string: "https://api.github.com/orgs/\(orgName)/repos" ) else {
            return Just([])
                .eraseToAnyPublisher()
        }

        return URLSession.shared.dataTaskPublisher(for: url)
            .map { $0.data }
            .decode(type: [Repository].self, decoder: JSONDecoder())
            .replaceError(with: [])
            .receive(on: RunLoop.main)
            .eraseToAnyPublisher()
    }

func loadBranchs(orgName: String, repoName: String) -> AnyPublisher<[Branch], Never> {
        guard let url = URL(string: "https://api.github.com/repos/\(orgName)/\(repoName)/branches") else {
            return Just([])
                .eraseToAnyPublisher()
        }

        return URLSession.shared.dataTaskPublisher(for: url)
            .map { $0.data }
            .decode(type: [Branch].self, decoder: JSONDecoder())
            .replaceError(with: [])
            .receive(on: RunLoop.main)
            .eraseToAnyPublisher()

    }

这两个函数分别工作,但我不知道如何结束[BranchSectionModel]。我猜使用flatMap和sink,但不明白如何。
我不明白如何在一个线程中合并这两个请求。

6ljaweal

6ljaweal1#

当你想把一个发行商变成另一个发行商时,.map.switchToLatest。在这种情况下,因为你也想把一个发行商变成多个(然后再变成一个),MergeMany也是一个有用的工具:

loadRepositorys(orgName: orgName)
    .map { repos in
        Publishers.MergeMany(repos.map { repo in
            loadBranchs(orgName: orgName, repoName: repo.name)
                .map { branches in
                    BranchSectionModel(name: repo, branchs: branches)
                }
        })
        .collect(repos.count)
    }
    .switchToLatest()
    .sink { result in
        print("---")
        print(result)
    }
    .store(in: &cancellables)

虽然我是合并的忠实粉丝,但我不认为它特别适合这项任务,与async/await相比,async/await可能会更少一些混乱,看起来更干净。作为一个学习练习,这是一个很好的练习,但如果你要在真实的世界中解决这个问题,async/await可能会是我的首选。

相关问题