게시글, 홈 화면 등등 일부 화면에서 데이터를 받아와 UI에 바인딩시킬때 상대적으로 느리게 받아와지는 느낌이 들었다
기존에 나와있는 개발상황은 거의 진행되었으나 해당 프로젝트를 어떻게 개선시킬 수 있을지 고민해보는 시간을 가졌다
switch statusCode {
case 200..<300:
if decodedData.data != nil {
return observer(.success(.success(decodedData.data!)))
}
return observer(.success(.success(EmptyModel() as! T)))
case 400..<500:
return observer(.failure(HaramError.requestError))
case 500..<600:
return observer(.failure(HaramError.serverError))
default:
return observer(.failure(HaramError.unknownedError))
}
기존 API를 호출하는 코드의 일부이다, 해당 reuest함수의 리턴값으로는 일반적으로 네트워크 호출에 대한 결과만을 반환하기위해서 Single을 이용하였고 Single의 Element로 Observable<Result<T, HaramError>>타입을 가지게 개발하였다
허나 이러한 리턴타입으로 인해 위 코드에서처럼 하나의 리턴을 던져줌에도 뎁스가 깊어보이고 불필요하다는 생각이 들었다
또한 API호출에 대한 오류에 따른 동작을 구현해주어야했는데 이와같은 리턴값은 onNext를 통한 일반적으로 성공적으로 값을 반환하는 경우에도 성공과 실패에 따른 불필요한 로직을 추가한다는 문제가 인지되었다
switch statusCode {
case 200..<300:
if decodedData.data != nil {
return observer.onNext(.success(decodedData.data!))
}
return observer.onNext(.success(EmptyModel() as! T))
case 400..<500:
return observer.onNext(.failure(HaramError.requestError))
case 500..<600:
return observer.onNext(.failure(HaramError.serverError))
default:
return observer.onNext(.failure(HaramError.unknownedError)
}
나는 이와같은 문제를 그냥 리턴타입을 Single타입으로 던져주었다, 이렇게 코드를 개선하니 확실히 눈에 띄게 코드가 줄어들었고 성공과 실패에 대한 의미가 구분지어줄 수 있었다
또한 API를 통해 값을 받아올 때 특정 에러에 대한 로직처리를 할때 공통적으로 compactMap을 통한 결과값이 nil값을 받는지에 대한 코드를 줄일 수 있었다
viewModel에서 subscribe를 통해 값을 받아올때에도 onSuccess, onFailure를 이용해 확실히 오류인지 아닌지에 대한 처리를 쉽게 이해할 수 있었다
다양한 레퍼런스를 통해 찾아본 결과 swift의 URLSession은 기본적으로 캐시를 이용해 값을 캐시화시키고 기존 값과 크게 다를바가 없다면 이처럼 데이터를 캐시화하는것은 매우 유용한 로직일 것이다
하지만 실시간으로 값이 천차만별로 변하고 호출할때마다 새로운 데이터를 받아와야하는 경우에는 이같은 캐시화는 무의미한 리소스를 낭비하는 것이며 최신화된 데이터를 사용자로 하여금 받아지는것이 힘들어질 것이다
위와 같은 문제를 해결할 수 있는 것이 Cache-control이라 하는 헤더값을 통해 해당 API는 캐시화시키지말아줘라고하는 부분을 추가할 필요가 있음을 깨달았다
case .noCache:
// 토큰이 존재하지 않는 경우 default 리턴
guard let token = UserManager.shared.accessToken else {
return HeaderType.default.toHTTPHeader
}
// default 헤더 값에 `Authorization token` 및 `Content-Type` 추가
var defaultHeaders = HTTPHeaders.default
defaultHeaders.add(.authorization(bearerToken: token))
defaultHeaders.add(.contentType("application/json"))
defaultHeaders.add(name: "Cache-Control", value: "no-store")
return defaultHeaders
}
* Cache-control을 적용시킬 수 있는 방법으로 위 코드에서철 ㅁ헤더값의 Cache-control의 value값을 no-store을 넣어주는 방법이 있을 수 있다
> 다른 방법으로는 URLSessionConfiguration을 이용하여 캐시화시키지않음을 언급하는 방법 또한 존재한다
URL의 body값으로 인코딩한 값을 넣는 역할만을 하는 Entity이든 API호출을 통해 받은 응답값을 디코딩하기위한 Entity 또한 모두 Codable을 채택하고 있었다
Codable프로토콜은 Encodable & Decodable 프로토콜 2개를 채택하기에 하나의 역할만을 하는 Entity에 Codable을 채택하는것은 불필요하다 생각하여 이를 역할에 맞게 프로토콜을 채택해주었다