지난 포스트에서 Generic을 활용하여 코드를 단축하는 방법에 대해 연구해보았다.
그렇다면 이번엔 정말로 긴, 긴 코드를 줄여보자. 단순히 Decode정도가 아닌.
Problem
"피플"은 Single, Observable을 정말 많이 리턴한다.
코드를 살펴보자
func fetchFive() -> Single<[CalendarModel]> {
return Single.create() { observable in
let urlString = "\(self.baseUrl)/api/v1/account/calendar/after/test?minusDay=5&accountUuid=\(UserDatabaseManager.shared.myUserModel!.uuid)"
guard let url = URL(string: urlString) else {
observable(.error(DatabaseFetchingErrorType.urlFailedError))
return Disposables.create()
}
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue(UserDatabaseManager.shared.jwtToken, forHTTPHeaderField: "X-AUTH-TOKEN")
request.timeoutInterval = 10
AF.request(request).responseData { response in
switch response.result {
case .success(let data):
if let calendarModelArray = self.decode(jsonData: data, type: [CalendarModel].self) {
observable(.success(calendarModelArray))
print("[Calendar 5] fetching 성공")
} else {
observable(.success([]))
}
case .failure(let err):
print("🚫[Calendar 5] 에러 \(err)")
observable(.error(DatabaseFetchingErrorType.fetchingFailedError))
}
}
return Disposables.create()
}
}
Calendar Manager의 fetchFive라는 함수이다.
최근 5개의 CalendarModel을 리턴한다. Single 로 리턴한다.
다른 코드들 또한 이러한 형식을 많이 따른다.
request에 필요한 파라미터를 담고, 리퀘스트를 디코딩해서 결과를 얻어 Bind한다.
그런데, 벌써 코드가 30~40줄 정도가 되는 것 같다.
이러한 함수가 20 ~ 30개가 되니 코드의 양은 너무 방대해져버렸다.
Param과 Path를 인자로 받아 원하는 타입의 Single을 리턴하는 함수를 만들어보자.
func single<T: Codable>(path: String, type: T.Type, params: [String: Any]?) -> Single<T>
선언은 이렇게한다.
path 와 type, 그리고 파라미터는 없을 수도 있으니까 옵셔널로 받는다.
var queryParams = ""
if let params = params {
queryParams = params.map { k, v in "\(k)=\(v)" }.joined(separator: "&")
}
var fullPath = path.hasPrefix("http") ? path : self.baseUrl + path
if queryParams.count > 0 {
fullPath += "?" + queryParams
}
파라미터에대한 처리는 위처럼 해준다.
&로 key=value를 묶어 마지막에 path 뒤에 ? 를 붙여 fullPath를 완성한다.
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue(UserDatabaseManager.shared.jwtToken, forHTTPHeaderField: "X-AUTH-TOKEN")
request.timeoutInterval = 10
AF.request(request).responseData { response in
switch response.result {
case .success(let data):
if let returnData = self.decode(jsonData: data, type: type.self) {
observable(.success(returnData))
print("[\(type)] fetching 성공")
} else {
observable(.error(DatabaseFetchingErrorType.encodingFailedError))
}
case .failure(let err):
print("🚫[\(type)] 에러 \(err)")
observable(.error(DatabaseFetchingErrorType.fetchingFailedError))
}
}
return Disposables.create()
그리고 나서는 똑같이 함수를 적어 리턴해주면 제네릭 함수가 완성된다.
결론
func fetchFive() -> Single<[CalendarModel]> {
return single(path: fivePath, type: [CalendarModel].self, params: ["accountUuid": UserDatabaseManager.shared.myUserModel!.uuid])
}
세 줄로 줄었다.
하지만 지금당장은 Single 만 사용을 해보았고, 다른 복잡한 형태의 제네릭 함수구현을 위해서는 조금 더 공부를 해보아야겠다.