[TDH-31] 로그인 api 및 토큰 저장 처리부 구현#12
Conversation
| } | ||
|
|
||
| struct SsoResponse: Codable { | ||
| let userId: Int64 |
There was a problem hiding this comment.
- 특별한 경우가 아니라면 정수 자료형은
Int를 사용하는게 좋습니다.Int는 시스템 아키텍처 종류에 따라Int64,Int32등으로 사용됩니다. - Swift는 type safe한 언어라서, Int64는 Int와 충돌을 일으켜 불필요한 conversion이 필요하게 되는 단점도 있습니다.
|
|
||
| extension LoginApi { | ||
| func loginWithSso(platformType: PlatformType, userAgent: String, accessToken: String, completion: @escaping (SsoResponse?, Error?) -> Void) { | ||
| loginSession.request(Urls.compose(path: Paths.requestSso), method: .post, parameters: ["platformType": platformType, "userAgent": userAgent, "accessToken": accessToken]) |
There was a problem hiding this comment.
@songmilee
Method 호출부 코드가 너무 길어지면 parameter를 기준으로 적절하게 개행하시면 가독성이 더 높아질 것입니다
| switch response.result { | ||
| case .success(let result): | ||
| completion(result, nil) | ||
| case .failure(let error): | ||
| completion(nil, error) | ||
| } |
There was a problem hiding this comment.
@songmilee
completion closure의 parameter type을 Result<SsoResponse, Error>으로 사용하면 코드가 더 깔끔해 질 것 같습니다
|
|
||
|
|
||
| final class TokenManager { | ||
| public static let shared = TokenManager() |
| if let tokenData = UserDefaults.standard.data(forKey: key) { | ||
| let token = try? JSONDecoder().decode(SsoResponse.self, from: tokenData) | ||
| self.token = token | ||
| } |
There was a problem hiding this comment.
@songmilee
guard문을 사용하면 depth가 깊어지지 않고 깔끔하게 코드를 작성할 수 있습니다.
init() {
guard let tokenData = UserDefaults.standard.data(forKey: key) else { return }
token = try? JSONDecoder().decode(SsoResponse.self, from: tokenData)
}| if let data = try? JSONEncoder().encode(token) { | ||
| UserDefaults.standard.set(data, forKey: key) | ||
| UserDefaults.standard.synchronize() | ||
|
|
||
| self.token = token | ||
| } |
There was a problem hiding this comment.
@songmilee
여기도 guard문을 사용하면 더 간단하게 작성할 수 있어 보입니다
|
|
||
| final class TokenManager { | ||
| public static let shared = TokenManager() | ||
| var token: SsoResponse? = nil |
There was a problem hiding this comment.
@songmilee
아래에 구현 방식들을 보니, token은 computed property로 만들어 사용하는게 더 편해 보이네요
final class TokenManager {
var token: SsoResponse? {
get {
guard let tokenData = UserDefaults.standard.data(forKey: key) else { return nil }
return try? JSONDecoder().decode(SsoResponse.self, from: tokenData)
}
set {
guard let data = try? JSONEncoder().encode(token) else { return }
UserDefaults.standard.set(data, forKey: key)
}
}
}이런 형태의 computed property는 property wrapper를 사용하면 더 간단하게 사용할 수도 있습니다.
final class TokenManager {
@SSOResponse
var token: SsoResponse?
}| } | ||
|
|
||
| extension LoginStore { | ||
| func isLogin() -> Bool { |
There was a problem hiding this comment.
@songmilee
이렇게 parameter가 없고 어떤 값을 반환하기 위해 명사형으로 이름을 작성하게 되는 method들은 readonly property로 작성하면 호출부에서 더 자연스럽게 사용할 수 있습니다.
// 1.
if isLogin() { ... }
// 2.
if isLogin { ... }| return false | ||
| } | ||
|
|
||
| func login(email: String, password: String, completion: @escaping (Result<Bool, Error>) -> Void) { |
There was a problem hiding this comment.
@songmilee
false를 반환해야 하는 상황에서도 Error를 throw하면 어떨까요?
.success(false)가 반환되는 상황에서는 로그인 할 수 없을텐데요. '성공'한 case로 false라는 값을 반환하는 것 보다 error를 반환하는게 더 자연스럽지 않을까요?
| HStack(spacing: 16) { | ||
| LoginButton(type: .kakao) { | ||
| loginStore.kakaoLogin() | ||
| loginStore.kakaoLogin { result in switch result { |
요약
리뷰 요청 사항