์ฐ๋ฆฌ๊ฐ Firebase Firestore RestAPI ๋ฅผ ์ฌ์ฉํ๋ฉด์,
๊ธฐ์กด์ ์ฌ์ฉํ๋ SDK ๋ฅผ ์ฌ์ฉํ ๋ฉ์๋๋ฅผ ๋ค์ ์๋ก ๊ตฌํํด์ผํ๋ค.
๋จผ์ ์ฐ๋ฆฌ๋ Firestore๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ ์ค๊ณ , Firestore ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์กํ๊ธฐ ์ํด
URLSession ์ ์ฌ์ฉํด์ ๋คํธ์ํฌ ์์ ์ ์ฒ๋ฆฌํ๋ค.
๋คํธ์ํฌ ์์ ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด ๋ค์ํ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฐฉ์์ค Combine์ ์ฑํํ์ฌ
Combine ๊ณผ URLSession ์ด ๋ ์กฐํฉ์ ์ฌ์ฉํด๋ณด๊ธฐ๋ก ํ๋ค.
๋จผ์ ํฐ ๊ตฌ์กฐ๋ก ํ๋ฒ ์๊ฐํด๋ณด๋ฉด, ๐ค
- URL ์ ๋ํ ๋ฐ์ดํฐ ์์ ์ ์ํ Publisher ์
- Publisher ๋ฅผ ๊ตฌ๋ ํด์ Publisher์์ ๋ฐ์ํ๋ ๊ฐ์ ์ฒ๋ฆฌํ Subscriber ๊ฐ ํ์ํฉ๋๋ค.
๊ทธ๋์ ์ด๋ป๊ฒ ๋คํธ์ํฌ ๋ ์ด์ด๋ฅผ ๊ตฌํํ ๊ฒ์ด๋ ! ๐ค
- ์ ๋ ๋จผ์ ์์ฑ๋ URL ์์ฒญ์ ์ฌ์ฉํ์ฌ Publisher๋ฅผ ์์ฑํด์ฃผ๋ ๋ฉ์๋์
- ์์ฑ๋ Publisher๋ฅผ ๊ตฌ๋ ํ๊ณ , ๋ฐ์ํ๋ ๊ฐ์ ์ฒ๋ฆฌํ ๋ฉ์๋๋ฅผ ๋๋ ์ ๊ตฌํํ ๊ฒ๋๋ค!

์ด๋ฒ ํ๋ก์ ํธ๋ MVVM ํจํด์ผ๋ก ๊ตฌ์ฑ์ ํ๊ณ , ์ ์ฒด์ ์ธ ๋คํธ์ํฌ ์์ ๋ ์ด์ด๋ ์ด๋ ๊ฒ ๊ตฌ์ฑ๋์ด์์ต๋๋ค. ๐๐ป
๋จผ์ Publisher ๋ฅผ ์์ฑํด์ฃผ๋ ๋ฉ์๋๋ ์ด๋ ์ต๋๋ค.
static func getUser(nextPageToken: String) -> AnyPublisher<UserResponse, Error> {
do {
let request = try UserRouter.get(nextPageToken: nextPageToken).asURLRequest()
return URLSession
.shared
.dataTaskPublisher(for: request)
.map{ $0.data }
.decode(type: UserResponse.self, decoder: JSONDecoder())
.eraseToAnyPublisher()
} catch {
return Fail(error: HTTPError.requestError).eraseToAnyPublisher()
}
}
dataTaskPublisher ?
๋จผ์ URLSession ์ ๋ฉ์๋์ธ dataTaskPublisher(for:) ๋ฅผ ์ฌ์ฉํ๋๋ฐ์!
์ด dataTaskPublisher(for:) ๋ ๋ฌด์์ ํ๋ ์นญ๊ตฌ๋๋ฉด ?
URLSession์ ๋ฉ์๋์ด๊ณ , Combine ํ๋ ์์ํฌ์์ ์ฌ์ฉํ ์ ์๋ Combine Publisher๋ฅผ ๋ฐํํฉ๋๋ค.
์ด Publisher๋ฅผ ์ฌ์ฉํด ์ฐ๋ฆฌ๋ ๋น๋๊ธฐ์ ์ธ ๋คํธ์ํฌ ๋ฐ์ดํฐ ์์ ์ ์ํํ๊ณ , ๊ฒฐ๊ณผ๋ฅผ ์ฒ๋ฆฌํ ์ ์๋๊ฒ์ด์ฃ !
dataTaskPublisher(for:) ๊ฐ ๋ฐฉ์ถํ Publisher๋ ๋ฐ์ดํฐ ์์ ์ด ์์๋๋ฉด ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ํค๊ณ ,
์์ ์ด ์๋ฃ๋๋ฉด ์๋ฃ ์ด๋ฒคํธ๋ฅผ ๋ฐฉ์ถํฉ๋๋ค. ์์ ๋์ค์ ๋ฐ์ํ๋ ์ค๋ฅ๋ ์๋ฌ ์ด๋ฒคํธ๋ก ์ฒ๋ฆฌํฉ๋๋ค.
(์์ ๋ฉ์๋,,, ๋๋ฌด ,,, ๋ญ๊ฐ ๋ง์ฃ ? ํ๋์ฉ ์ดํด๋ณผ๊ฒ์ !!! ๐ค)
- UserRouter.get(nextPageToken: nextPageToken).asURLRequest(): UserRouter๋ URL ์์ฒญ์ ์์ฑํ๋ ์ด๊ฑฐํ ๋ผ์ฐํฐ์์ get(nextPageToken:) ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ URL ์์ฒญ์ ์์ฑ.
- URLSession.shared.dataTaskPublisher(for: request): ์์ฑ๋ URL ์์ฒญ์ ์ฌ์ฉํด์ dataTaskPublisher(for:) ๋ฉ์๋๋ฅผ ํธ์ถ.
- .map{ $0.data}: Publisher๋ก๋ถํฐ ๋ฐ์ (data: Data, response: URLResponse) ํํ์ ๋ฐ์ ๋ฐ์ดํฐ ๋ถ๋ถ๋ง ์ถ์ถ. .data ํ๋กํผํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ์ ์ ๊ทผ.
- .decode(type: UserResponse.self, decoder: JSONDecoder()): ์ถ์ถํ ๋ฐ์ดํฐ๋ฅผ JSONDecoder() ๋ฅผ ์ฌ์ฉํ์ฌ JSON ๋ฐ์ดํฐ๋ฅผ UserResponse ํ์ ์ผ๋ก ๋์ฝ๋ฉ.
- .eraseToAnyPublisher(): decode ๋ฉ์๋์ ๋ฐํ ํ์ ์ Publishers.Decode ํ์ ์ด์ง๋ง, ๋ฐํ ํ์ ์ AnyPublisher<UserResponse, Error>๋ก ๋ณํํ๊ธฐ ์ํด eraseToAnyPublisher()๋ฅผ ํธ์ถ.
- return Fail(error: HTTPError.requestError).eraseToAnyPublisher(): ์์ฒญ ์์ฑ ๋๋ ๋คํธ์ํฌ ์์ ์ค์ ์ค๋ฅ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ, HTTPError.requestError๋ฅผ ๊ฐ์ง Fail Publisher๋ฅผ ๋ฐํ. ์ด ๊ฒฝ์ฐ์๋ eraseToAnyPublisher()๋ฅผ ํธ์ถํ์ฌ ๋ฐํ ํ์ ์ AnyPublisher<UserResponse, Error>๋ก ๋ณํ.
getUser ๋ฉ์๋์ ๋ฐํ๊ฐ์ ๊ฒฐ๊ตญ AnyPublisher<UserResponse, Error> ๊ฐ ๋๋๋ฐ,
์ด๋ ๋น๋๊ธฐ ์์ ์ ๊ฒฐ๊ณผ๊ฐ
- ์ฑ๊ณต์ ์ธ ๊ฒฝ์ฐ UserResponse ํ์์ผ๋ก
- ์คํจํ ๊ฒฝ์ฐ Errorํ์ ์ผ๋ก ์ ๋ฌํ๊ธฐ ์ํจ์ ๋๋ค.
์ด๋ฅผ ํตํด ์์ ์ ์ฑ๊ณต ๋๋ ์คํจ์ ๋ฐ๋ผ ์ ์ ํ๊ฒ ์ฒ๋ฆฌ๋ฅผ ํ ์ ์๊ฒ ๋๋๊ฑฐ์ฃ !
์ด๋ ์ต๋๋ค … ์ ๋ง ,,, ์ฝ์ฃ ์ ?
๊ทธ๋ผ Publisher๋ฅผ ์์ฑํ๋ฉด ๊ตฌ๋ (Subscription) ์ ์ด๋ป๊ฒ ํ ๊น์ ?
๊ทธ๋ ๋ค๋ฉด ์์ ๋ฉ์๋์์ Publisher๋ฅผ ๋ฐํํ๋ฉด ์ด์ ์ด๋ค ์์ ์ ์ํํด์ผํ ๊น์ ?
์ด ๋ฐํ๋ Publisher๋ฅผ ๊ตฌ๋ ํ์ฌ ์์ ์ด ์ํ๋๋ฉด, ๋ฐ์๋ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํด์ผ๊ฒ ์ฃ !
๋ฐ๋ก ์ด ์์ ์ ViewModel ์์์ ์ํ๋ฉ๋๋ค. !
- ๋จผ์ ViewModel ์์ ์ ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ณ , ๋ฐ์ดํฐ ์ํ๋ฅผ ๊ด๋ฆฌํ “users” (@Published) ๋ณ์๋ฅผ ์ ์ธํด์ค๋๋ค.
- fetchUsersSuccess ๋ผ๋ PassthroughSubject ๋ฅผ ์ ์ธํด์ค๋๋ค.
PassthroughSubject ๋ publisher์ด๊ณ , ์์ ์ด ๋๋๋ฉด send ๋ฉ์๋๋ฅผ ํธ์ถํด์ ์ ๊ฐ์ ๋ฐํ์์ผ ์ค๊ฒ๋๋ค.
@Published var users = [UserDocument]()
var fetchUsersSuccess = PassthroughSubject<[UserDocument], Never>()
func fetchUser() {
UserService.getUser()
.receive(on: DispatchQueue.main)
.sink { (completion: Subscribers.Completion<Error>) in
// ์๋ฌ๋ฅผ ์ฒ๋ฆฌํ๋ ์ฝ๋ ์์ฑ
switch completion {
case .finished:
print("์์
์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋์์ต๋๋ค.")
case .failure(let error):
print("์๋ฌ ๋ฐ์: \(error)")
} receiveValue: { (data: UserResponse) in
// ๋ฐ์ ๊ฐ ์ฒ๋ฆฌ
users = data.document
self.fetchUsersSuccess.send(data.documents)
}.store(in: &subscription)
}
๋จผ์ fetchUser ๋ฉ์๋์์ UserSerivce.getUser() ๋ฅผ ํธ์ถํด์ Publisher๋ฅผ return ํ๋ฉด
sink ๋ฅผ ํตํด ๊ตฌ๋ ์ ํ๊ฒ ๋๋๋ฐ์,
sink ?
์ฌ๊ธฐ์ ์ฃผ๋ชฉํด์ผํ ๋ฉ์๋๋ sink ์ ๋๋ค ! ํ๋ฒ ์์๋ณผ๊ฒ์
๋ฐ๋ก ์ด sink ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด, puslisher ์ subscriber ๋ฅผ ์ฐ๊ฒฐํ๋ subscription์ ์์ฃผ ์ฝ๊ฒ ๋ง๋ค ์ ์์ต๋๋ค.
๋ ์ด sink ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ Publisher ์์ ๋ฐ์ํ๋ ๊ฐ ๋๋ ์๋ฃ ๋ฐ ์๋ฌ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
sink ๋ฉ์๋์ receiveCompletion ํด๋ก์ ธ์์ completion ๋งค๊ฐ๋ณ์ํ์ ์
Subscribers.Completion<Error> ์ ๋๋ค . Subscribers.Completion์ Combine ํ๋ ์์ํฌ์์ ์๋ฃ ๋ฐ ์๋ฌ ์ด๋ฒคํธ๋ฅผ ๋ํ๋ด๊ธฐ ์ํด ์ฌ์ฉ๋๋ ์ด๊ฑฐํ์ ๋๋ค.
์ด ์ด๊ฑฐํ์ ์๋ ๋๊ฐ์ง ์ผ์ด์ค๋ฅผ ๊ฐ์ง๊ณ ์๊ณ ๊ฐ๊ฐ์ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค!
- .finished : ์์ ์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋ ๊ฒฝ์ฐ
- .failure : ์์ ์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋์ง ๋ชปํ ์ฑ ์๋ฌ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ
receivedValue ?
sink ๋ฉ์๋ ๋ฐ๋ก ๋ค์์ ๋ณด์ด๋ receivedValue ํด๋ก์ ธ๋
sink ๋ฅผ ํตํด pulisher ๋ฅผ ๊ตฌ๋ ํ๊ณ , Publisher๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ํ์๋ ํธ์ถ๋๊ณ ,
์ด ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด ์ฌ์ฉ๋ฉ๋๋ค.
๊ทธ๋์ ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ค๋ฉด ๊ทธ ๋ฐ์ดํฐ๋ฅผ VM ์ ํ๋กํผํฐ์ธ users ๋ฐฐ์ด์ ์ ์ฅํด์ฃผ๊ฒ ๋๋๊ฑฐ์ฃ !
์ฌ๊ธฐ๊น์ง URLSession ๊ณผ Combine์ ์ฌ์ฉํด์ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๊ณ , ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ ์ฒ๋ฆฌ ํ๋ ๊ณผ์ ์ ์์๋ดค์ต๋๋ค.
๋ค์์ URLSession ์ URL ์ ๋ง๋๋ ๊ณผ์ ์ ๋ํด์ ์์๋ณผ๊ฒ์ฉ
(์์ ๋คํธ์ํฌ ๋ ์ด์ด์ ์๋ Router ๋ ๋ญํ๋ ์นญ๊ตฌ์ผ๊น ? )
To be Continue ~
์ค๋๋ ํด๊ฒฐ์ ~ ๐
'ํ๋ก์ ํธ ๐ ๏ธ > iOS' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| ์ฑ์ด ์งฑ์ปค์ ์ ๋ฐ์ดํธ ํ ๊ฑฐ ๋ฐฑ๋ง๊ฐ! (0) | 2023.06.10 |
|---|---|
| Router๊ฐ ๋ญํ๋ ์น๊ตฌ์ผ? (0) | 2023.06.10 |
| Combine(3): Operator (0) | 2023.06.10 |
| Combine(2): Subject (0) | 2023.06.10 |
| Combine(1): Publisher, Subscriber! (0) | 2023.06.10 |