๐ฉ ํต์ ์๋ต์ผ๋ก ์จ ๋ฐ์ดํฐ๋ฅผ UI์ ๋ฐ์ํ๋ ๋ฐฉ๋ฒ ๊ณ ๋ฏผ๊ธ
โ ๏ธ ๋ด ์ฝ๋์ ๋ฌธ์ ์
โฌ๏ธfirestore
์ CRUD๋ฅผ ๊ด๋ฆฌํ๋ ๊ฐ์ฒด, ProjectFirestoreManager
์ ํต์ ์ ํตํด Status
์ ํด๋นํ๋ Project
๋ฅผ ์ฝ์ด์ค๋ ๋ฉ์๋
// ProjectFirestoreManager
func read(of group: Status, completion: @escaping (Result<[[String : Any]], FirestoreError>) -> Void) {
self.db.collection(FirestorePath.collection).whereField("status", isEqualTo: group.rawValue)
.getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
completion(.failure(.doucmentNotExist))
} else {
var datas: [[String: Any]] = []
for document in querySnapshot!.documents {
print("\(document.documentID) => \(document.data())")
datas.append(document.data())
}
completion(.success(datas))
}
}
}
โฌ๏ธ ์ฑ์ ํต์ฌ ๋น์ง๋์ค๋ก์ง์ ์ฒ๋ฆฌํ๋ ProjectManager
๊ฐ์ฒด
status์ ํด๋นํ๋ [Project]
๋ฅผ ์ฝ์ด์ ๋ฆฌํดํ๋ ๋ฉ์๋
(๋ฐ์ดํฐ์์ค ๊ฐ์ฒด๋ง ๋ฐ๊ฟ์น๊ธฐํด๋ ๊ธฐ์กด ์ฝ์ด๋ฐ์ดํฐ๋งค๋์ ์ ์ธํฐํ์ด์ค๋ฅผ ๋์ผํ๊ฒ ๊ฐ์ ธ๊ฐ๊ณ ์ถ์๋ค. ์ด๊ฒ์ด ๋ฌธ์ ์ ์์...)
// ProjectManager
func readProject(of status: Status) -> [Project]? {
var returnProjects: [Project]?
// ํต์ ์ฝ๋๋ ๋น๋๊ธฐ๋ค.
projectDataManager.read(of: status) { result in
switch result {
case .success(let dicts):
let projects = dicts.compactMap { dict in
return Project(identifier: dict["identifier"] as? String,
title: dict["title"] as? String,
deadline: dict["deadline"] as? Date,
description: dict["description"] as? String,
status: dict["status"] as? Status)
}
returnProjects = projects
case .failure(let error):
print(error.localizedDescription)
returnProjects = nil
}
}
// ๐คท๐ปโโ๏ธ ์๋ต์ด ์ค๊ธฐ์ ์ ๋ฆฌํด๋จ. ๊ทธ๋์ ํญ์ nil ๋ฐํ
return returnProjects
}
ํต์ ์ด ๋์ฐฉํ๊ธฐ์ ์ ๋ฆฌํดํด์ ํญ์ nil์ ๋ด๋ณด๋ธ๋ค.
// ๋ทฐ์ปจํธ๋กค๋ฌ์์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์ ๋ฐ์ํ๋ ๋ถ๋ถ
func applySnapshotToCell() {
// ํญ์ nil์ด ๋ค์ด์จ๋ค.
let projects = delegate?.readProject(of: projectStatus)
var snapShot = NSDiffableDataSourceSnapshot<Section, Project>()
snapShot.appendSections([.main])
snapShot.appendItems(projectsToApply ?? [], toSection: .main)
self.dataSource.apply(snapShot, animatingDifferences: true, completion: nil)
}
๊ทธ๋์ ๋ทฐ์ปจ์์๋ ํญ์ nil
์ ๋ฐ๋๋ค.
UI์ ๋ฐ์ดํธย ์ฝ๋๋ย ๋ฆฌํดํ๋ฉดย ์๋จ
ํต์ +UI๊ฐย ํ๋์ย ํ์คํฌ๋กย ๋ฌถ์ฌ์ผํจ
(์ด๋ง์ย ๋ชจ๋ธ์ด๋ย ๋ทฐ๊ฐย ์ข ์์ฑ์ดย ์๊ธธย ์ย ๋ฐ์ย ์๋ค)
๐ ํด๊ฒฐ ๋ฐฉ๋ฒ
1๏ธโฃย ๋ทฐ ์ปจํธ๋กค๋ฌ์ย read ๋ฉ์๋์์ ๋งค๊ฐ๋ณ์๋กย completion
์ ๋ฐ์์ ๋๊ฒจ์ฃผ๋ ๋ฐฉ๋ฒ. completion
์๋ ๋ทฐ๋ฅผ ์
๋ฐ์ดํธ ์ํค๋ ์ฝ๋๊ฐ ๋ค์ด๊ฐ
- ๋ก์ปฌ์ ๊ฒฝ์ฐ comlpetion์ด ํ์ ์์
- ๋ฐ์ดํฐ๊ฐ ์ฐ์ด๋ ๊ณณ์์ ์ ์ ํ ์ฒ๋ฆฌ๋ฅผ ํ ์ ์์ด์ ์์จ์ฑ์ด ๋์
- ๋จ์
- ์ปจํธ๋กค๋ฌ์ ๋ชจ๋ธ์ ๋ก์ง์ด ์ฒจ๊ฐ ๋์ ์ญํ ๋ถ๋ฆฌ๊ฐ ์ด๋ ค์,,
- ๋ง์ฝ ๋ฐ์ ๋ฐ์ดํฐ๊ฐ ์ปจํธ๋กค๋ฌ์ ์ฌ๊ธฐ์ ๊ธฐ์ ์ฌ์ฉ๋๋ค๋ฉด?
- ๋ฐ์ดํฐ ์์ ์ ๋ฐ๋ฅธ ํ์ ์์ ์ ํ์ด๋ฐ์ ํธ๋ค๋งํด์ผํจ (ํ์ด๋ฐ ๋ง์ถ๊ธฐ ์ด๋ ต)
2๏ธโฃย ProjectManager
๋ธ๋ฆฌ๊ฒ์ดํธ๋ก ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ โ
- ๋ฐ์ดํฐ๋ฅผ ๋ฐ๋ ์ธํฐํ์ด์ค๋ฅผ
request
๋ก ์๋ก ๋ง๋ค๊ณ , - ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฉ์๋๋ฅผ ๋ธ๋ฆฌ๊ฒ์ดํธ๋ก ์ฒ๋ฆฌ.
3๏ธโฃย ํต์ ์ด ๋์ฐฉํ๋ฉด ๋ทฐ์ปจ์ผ๋ก ๋ ธํฐ๋ฅผ ๋ ๋ฆฌ๋ ๋ฐฉ๋ฒ ๐ โโ๏ธ
- ์ผ๋จ
nil
์ ๋ด๋ณด๋ธ๋ค. - ๋ ธํฐํผ์ผ์ด์ ์ผํฐ ์ฌ์ฉํด์ ๋ฐ์ดํฐ๊ฐ ์ฐ์ด๋ ๊ณณ์ ๋ ธํฐ๋ฅผ ๋ ๋ฆฐ๋ค.
- ๋จ์
- ํต์ ๊ฒฐ๊ณผ์ ๋ํ ๋ถ๋ถ์ ํ๋ ํ๋ ์ฑ๊ฒจ๊ฐ๋ฉด์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฐ์ดํธ ํด์ฃผ์ด์ผํ๋ค.โ ๏ธ
- ์ด๋ ๊ฒ ํ ๊ฒฝ์ฐ, ๊ด๋ จ ์ฝ๋์ ๋ํ ์ฌ์ด๋ ์ดํํธ๊ฐ ์๊ธธ ์ ์๋ค.โ ๏ธ๋ ธํฐํผ์ผ์ด์ ์ผํฐ๋ ์ ์ด๋ค.
4๏ธโฃย ๋น๋๊ธฐ ์ฝ๋๋ฅผ ๋๊ธฐ ์ฝ๋๋ก ๋ฐ๊ฟ
๊ฐ์ย ๋ฆฌํดํ๊ธฐย ์ ๊น์งย ๋ฆฌํดํ์งย ๋ชปํ๋๋กย ๋ธ๋ฝํ๊ณ (๋๊ธฐ ํ๋ฆ)
ํ๋ก์ ํธ๋ฅผย ์ฝ์ด์ย UI์
๋ฐ์ดํธย ํ๋ย ์ฝ๋๋ฅผย ๊ธ๋ก๋ฒ ํ์ย ๋ฃ๊ณ ย ๋น๋๊ธฐ๋กย ์ฒ๋ฆฌ
(UI๋งย ๋ฉ์ธํ์์ย ๋น๋๊ธฐ๋กย ์ฒ๋ฆฌํ๋๋ก)
DispatchQueue.global().async
โ ์คํจ โ (๋น๋๊ธฐ๋ฅผ ๋น๋๊ธฐ์ ๋ฃ๋ ๊ผด)
func readProject(of status: Status) -> [Project]? {
var returnProjects: [Project]?
DispatchQueue.global().sync {
// ๋น๋๊ธฐ ๋ฉ์๋๋ ๋ฐฑ๊ทธ๋ผ์ด๋ํ๋ก ์ผ์ ๋ณด๋ด๋๊ฒ ํ ์ผ์ ์ ๋ถ ์ด๋ฏ๋ก,
// ๊ธ๋ก๋ฒ ์ฑํฌ๋ก ์ฒ๋ฆฌํด์ฃผ์ด๋ ๋ฆฌํดํด๋ฒ๋ฆฐ๋ค
projectDataManager.read(of: status) { result in
switch result {
case .success(let dicts):
let projects = dicts.compactMap { dict in
return Project(identifier: dict["identifier"] as? String,
title: dict["title"] as? String,
deadline: dict["deadline"] as? Date,
description: dict["description"] as? String,
status: dict["status"] as? Status)
}
returnProjects = projects
case .failure(let error):
// TODO: - ์คํ๋ผ์ธ์ ์บ์ ์ฌ์ฉํ๋๋ก ํธ๋ค๋ง
print(error.localizedDescription)
returnProjects = nil
}
}
}
return returnProjects
}
DispatchGroup
์ ํ์ฉํ๋ ๋ฐฉ๋ฒ : ์ค๋ ๋๋ฅผ ๋ง์์ ๋๊ธฐ๋ก ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ
func readProject(of status: Status) -> [Project]? {
var returnProjects: [Project]?
let dispatchGroup = DispatchGroup()
dispatchGroup.enter()
cloudDataManager.read(of: status) { result in
switch result {
case .success(let dicts):
let projects = dicts.compactMap { dict in
return Project(identifier: dict["identifier"] as? String,
title: dict["title"] as? String,
deadline: dict["deadline"] as? Date,
description: dict["description"] as? String,
status: dict["status"] as? Status)
}
returnProjects = projects
dispatchGroup.leave()
case .failure(let error):
// TODO: - ์คํ๋ผ์ธ์ ์บ์ ์ฌ์ฉํ๋๋ก ํธ๋ค๋ง
print(error.localizedDescription)
returnProjects = nil
dispatchGroup.leave()
}
}
// โ๏ธ readProject๋ฅผ ํธ์ถํ๋ ์ค๋ ๋๊ฐ ์๋ต์ด ์ค๊ธฐ์ ๊น์ง ๋งํ
// ์ค๋ ๋๋ฅผ ๋ง๋ ๊ฑด ์ข์ ๋ฐฉํฅ์ ์๋
dispatchGroup.wait()
return returnProjects
}
์ ๋ฐฉ๋ฒ์ ์ ~๋ง ๋ฐฉ๋ฒ์ด ์์ ๋ ํ์.
๐ถ ๋๋์
๐ก ๋ท๋ถย UI ์ ๋ฐ์ดํธ๋ย ํญ์,ย ์ธ์ ๋ย ์๋ค๊ณ ย ์๊ฐํ๋ฉดย ๋ ย ๋ฏ.
์ต์ํด์ง์๐
๋น๋๊ธฐ์ ๊ฒฐ๊ณผ๊ฐ์ ํธ๋ค๋งํด์ผํ๋ ํจ์ ๊ฐ์ ๊ฒฝ์ฐ๋ ์ด๋ป๊ฒ ํ๋ช ํ๊ฒ ์ฒ๋ฆฌํ๋ ๊ฒ์ด ์ข์๊น?
์ปจํธ๋กค๋ฌ๊ฐ ๋ชจ๋ธ์ ๋ณด์ ํด์ผํ๊ธด ํ์ง๋ง,
๋ฐ์ดํฐ ๋ณํ์ ๋ฐ๋ผ ์ผ๊ด์ ์ผ๋ก ๊ด๋ จ ๋ฐ์ดํฐ, ๋ทฐ ์
๋ฐ์ดํธํ๋๊ฒ ๋ซ๊ฒ ๋ค.
๋ด ์๊ฐ์ ๋ฒ ์คํธ๋
๋ชจ๋ธ์ ํ๋ฆ์ ์ผ๊ด์ ์ด๋ฉด ์ข๊ฒ ๋ค.
์ฆ, ์ฐ๊ด๋ ๋ชจ๋ธ์ ์ผ๋ฐฉ์ ์ผ๋ก ๋ค ๊ฐ์ด ๋ณํํ๋๋ก.
๊ทธ๋ฆฌ๊ณ ๋ชจ๋ธ์ด ๋ณํํ๋ฉด ์๋์ผ๋ก ๋ทฐ๊ฐ ์ ๋ฐ์ดํธ ๋ ์ ์๋๋ก. ๋ชจ๋ธ์ observer๋ฅผ ๋ฑ๋ก!
์ด ํจํด์ด MVVM, ํด๋ฆฐ์ํคํ ์ณ์ผ๊น?
Author And Source
์ด ๋ฌธ์ ์ ๊ดํ์ฌ(๐ฉ ํต์ ์๋ต์ผ๋ก ์จ ๋ฐ์ดํฐ๋ฅผ UI์ ๋ฐ์ํ๋ ๋ฐฉ๋ฒ ๊ณ ๋ฏผ๊ธ), ์ฐ๋ฆฌ๋ ์ด๊ณณ์์ ๋ ๋ง์ ์๋ฃ๋ฅผ ๋ฐ๊ฒฌํ๊ณ ๋งํฌ๋ฅผ ํด๋ฆญํ์ฌ ๋ณด์๋ค https://velog.io/@yeahg_dev/ํต์ -์๋ต์ด-์ค๋ฉด-๋ฐ์ดํฐ๋ฅผ-UI๋ฅผ-Updateํ์์ ์ ๊ท์: ์์์ ์ ๋ณด๊ฐ ์์์ URL์ ํฌํจ๋์ด ์์ผ๋ฉฐ ์ ์๊ถ์ ์์์ ์์ ์ ๋๋ค.
์ฐ์ํ ๊ฐ๋ฐ์ ์ฝํ ์ธ ๋ฐ๊ฒฌ์ ์ ๋ (Collection and Share based on the CC Protocol.)
์ข์ ์นํ์ด์ง ์ฆ๊ฒจ์ฐพ๊ธฐ
๊ฐ๋ฐ์ ์ฐ์ ์ฌ์ดํธ ์์ง
๊ฐ๋ฐ์๊ฐ ์์์ผ ํ ํ์ ์ฌ์ดํธ 100์ ์ถ์ฒ ์ฐ๋ฆฌ๋ ๋น์ ์ ์ํด 100๊ฐ์ ์์ฃผ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์ ํ์ต ์ฌ์ดํธ๋ฅผ ์ ๋ฆฌํ์ต๋๋ค