はじめに
HTTP通信はいつもAlamofireを使用していて、URLSessionを使ったことがなかったので使ってみました。
サンプルアプリ
実装
View
ContentView.swift
import SwiftUI
struct ContentView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
List(viewModel.repositories.items) { item in
Label {
Text(item.name)
} icon: {
avatar(item: item)
}
}
.listStyle(.grouped)
}
func avatar(item: Item) -> some View {
AsyncImage(url: URL(string: item.owner.avatarURL), transaction: .init(animation: .default)) { result in
switch result {
case .success(let success):
success
.resizable()
.scaledToFit()
.clipShape(Circle())
default:
ProgressView()
}
}
}
}
ViewModel
ViewModel.swift
import Combine
import Foundation
final class ViewModel: ObservableObject {
@Published var repositories: SearchRepositories = .init(items: [])
private let url = "https://api.github.com/search/repositories?q=swift"
private var cancellable = Set<AnyCancellable>()
init() {
fetchSearchRepositories()
}
private func fetchSearchRepositories() {
URLSession.shared.dataTaskPublisher(for: URL(string: url)!)
.tryMap { data, _ in return data }
.decode(type: SearchRepositories.self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.sink { complete in
print(complete)
} receiveValue: { [weak self] response in
guard let self else { return }
self.repositories = response
}
.store(in: &cancellable)
}
}
Model
SearchRepositories.swift
import Foundation
// MARK: - SearchRepositories
struct SearchRepositories: Codable {
var items: [Item]
enum CodingKeys: String, CodingKey {
case items
}
}
// MARK: - Item
struct Item: Codable, Identifiable {
let id = UUID()
let name: String
let owner: Owner
let htmlURL: String
let itemDescription: String?
let languagesURL: String
let stargazersCount: Int
let language: String?
let forksCount: Int
let openIssuesCount: Int
enum CodingKeys: String, CodingKey {
case name
case owner
case htmlURL = "html_url"
case itemDescription = "description"
case languagesURL = "languages_url"
case stargazersCount = "stargazers_count"
case language
case forksCount = "forks_count"
case openIssuesCount = "open_issues_count"
}
}
// MARK: - Owner
struct Owner: Codable {
let login: String
let avatarURL: String
let url: String
let htmlURL: String
enum CodingKeys: String, CodingKey {
case login
case avatarURL = "avatar_url"
case url
case htmlURL = "html_url"
}
}
おわり
普通にURLSessionを使うとごちゃごちゃした感じになりますが、Combineで使うとスッキリしてますね。
これならAlamofireじゃなくて、URLSessionを採用してもいいかなと思いました。