💡 Github Profile Project Refactoring!
Refactoring이 이루어질 이전 코드는 위의 링크에서 참고하자
- Resource와 NetworkService를 이용해서 코드를 줄여보자
- Resource 를 이용해서 아래의 코드 줄여보기 = URLRequest 에 필요한 것을 만들어줌
let base = "https://api.github.com/"
let path = "users/\(keyword)"
let params: [String:String] = [:]
let header: [String:String] = ["Content-Type":"application/json"]
var urlComponents = URLComponents(string: base+path)!
let queryItems = params.map {(key: String, value: String) in
return URLQueryItem(name: key, value: value)
}
urlComponents.queryItems = queryItems
// base부터 header까지 URLRequest로 만들기
var request = URLRequest(url: urlComponents.url!)
header.forEach{ (key: String, value: String) in
request.addValue(value, forHTTPHeaderField: key)
}
- NetworkService 를 이용해서 아래의 코드 줄여보기
URLSession.shared
.dataTaskPublisher(for: request)
.tryMap{ result -> Data in
guard let response = result.response as? HTTPURLResponse,
(200..<300).contains(response.statusCode) else {
let response = result.response as? HTTPURLResponse
let statusCode = response?.statusCode ?? -1
throw NetworkError.responseError(statusCode: statusCode)
}
return result.data
}
// 받은 데이터를 가지고 JSONDecoder을 이용하여 UserProfile로 Decoding
.decode(type: UserProfile.self, decoder: JSONDecoder())
.receive(on: RunLoop.main)
.sink { completion in
print("completion: \(completion)")
switch completion {
case .failure(let error):
self.user = nil
case .finished: break
}
} receiveValue: { user in
// ViewController에 있는 User로 세팅!
self.user = user
}.store(in: &subscriptions)
그럼 Resource와 NetworkService 코드는 어떻게 생겼는가?
Resource.swift
// Resource.swift
import Foundation
struct Resource<T: Decodable> {
var base: String
var path: String
var params: [String: String]
var header: [String: String]
var urlRequest: URLRequest? {
var urlComponents = URLComponents(string: base + path)!
let queryItems = params.map { (key: String, value: String) in
URLQueryItem(name: key, value: value)
}
urlComponents.queryItems = queryItems
var request = URLRequest(url: urlComponents.url!)
header.forEach { (key: String, value: String) in
request.addValue(value, forHTTPHeaderField: key)
}
return request
}
init(base: String, path: String, params: [String: String] = [:], header: [String: String] = [:]) {
self.base = base
self.path = path
self.params = params
self.header = header
}
}
→ base, path, params, header만 받으면 알아서 request 반환
NetworkService.swift
// Network.swift
import Foundation
import Combine
///// Defines the Network service errors.
enum NetworkError: Error {
case invalidRequest
case invalidResponse
case responseError(statusCode: Int)
case jsonDecodingError(error: Error)
}
final class NetworkService {
let session: URLSession
init(configuration: URLSessionConfiguration) {
session = URLSession(configuration: configuration)
}
func load<T>(_ resource: Resource<T>) -> AnyPublisher<T, Error> {
guard let request = resource.urlRequest else {
return .fail(NetworkError.invalidRequest)
}
return session
.dataTaskPublisher(for: request)
.tryMap { result -> Data in
guard let response = result.response as? HTTPURLResponse,
(200..<300).contains(response.statusCode)
else {
let response = result.response as? HTTPURLResponse
let statusCode = response?.statusCode ?? -1
throw NetworkError.responseError(statusCode: statusCode)
}
return result.data
}
.decode(type: T.self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
}
→ load를 통해 request를 뽑아서, session에게 해당 request에 필요한 data task를 만들게 하여 데이터를 받아서 넘겨주는 것까지 하고있음
→ load에 resource만 넣으면 알아서 데이터가 처리됨.
1️⃣ NetworkService 객체 가져오기
let network = NetworkService(configuration: .default)
2️⃣ UserProfile 데이터를 받기 위한 Resource 생성 (Resource.swift 이용)
let resource = Resource<UserProfile>(
base: "https://api.github.com/",
path: "users/\(keyword)",
params: [:],
header: ["Content-Type":"application/json"]
)
3️⃣ NetworkService 객체의 load 함수를 이용해 자동 데이터 처리
network.load(resource)
.receive(on: RunLoop.main)
.sink { completion in
switch completion {
case .failure(let error):
self.user = nil
case .finished: break
}
} receiveValue: { user in
self.user = user
}.store(in: &subscriptions)
리펙토링 끝!
Reference
패스트캠퍼스 온라인 강의
'iOS > Toy project' 카테고리의 다른 글
[iOS : Toy Project] Todo List 만들기 (2) (0) | 2022.08.16 |
---|---|
[iOS : Toy Project] Todo List 만들기 (1) (0) | 2022.08.15 |
[iOS : Toy Project] Github Profile (1) (0) | 2022.07.16 |
[iOS : Toy Project] Apple Framework List (4) : Combine (0) | 2022.07.08 |
[iOS : Toy Project] Head Space Focus (2) : Navigation (0) | 2022.06.30 |