티스토리 뷰
[Firebase-DB] Firebase 예제 프로젝트(fetch) - Realtime DB에서 데이터 가져오기
eungding 2019. 5. 28. 14:10일단 feature브랜치로 firebase-fetch를 하나 만들고 작업을 시작합니다
memos의 어떤 변화든 관찰하겠다(?) 하는 코드인데,
let rootRef = Database.database().reference()
rootRef.child("memos").observe(.value) { snapshot in
let memosDic = snapshot.value as? [String: Any] ?? [:]
for (key, value) in memosDic {
print("key \(key) value\(value)")
}
}
딕셔너리를 출력해보면 key는 자동으로 만들어준 메모의 아이디 / value는 해당메모의 속성에 대한 딕셔너리이다
key -Lfu2XqePDtQA6KcyvJs
value{
title = "\Ud1a0\Ub9c8\Ud1a0\Uc0ac\Uae30";
}
key -Lfu-oGQnhiwrYXIq6Ch
value{
title = "\Uacc4\Ub780\Uc0ac\Uae30";
}
key -Lfu1yT46GqUtdvXRmaF
value{
title = "\Uc6b0\Uc720\Uc0ac\Uae30";
}
key -Lfu2cBWv7-CNnYD76UF
value{
title = "\Ub2f9\Uadfc\Uba39\Uae30";
}
그래서 FirebaseManager 클래스에 fetchAll 메소드를 이런식으로 만들어주고,
class func fetchAll() -> Observable<[Memo]> {
let rootRef = Database.database().reference()
rootRef.child("memos").observe(.value) { snapshot in
var memos: [Memo] = []
let memosDic = snapshot.value as? [String: Any] ?? [:]
for (key, _) in memosDic {
if let memoDic = memosDic[key] as? [String: Any], let memo = Memo(dic: memoDic) {
memos.append(memo)
}
}
}
return Observable.just(memos)
}
Memo 구조체에도 dictionary를 받는 옵셔널 이니셜라이저를 만들어준다
struct Memo {
let title: String
init(title: String) {
self.title = title
}
init?(dic: [String: Any]) {
guard let title = dic["title"] as? String else {
return nil
}
self.title = title
}
}
extension Memo {
func toDictionary() -> [String: Any] {
return ["title": title]
}
}
그리고 MemosViewModel에 가서
이니셜라이즈에 fetchAll하는 로직을 다음과 같이 추가해준다
struct MemosViewModel {
struct State {
var memos: BehaviorRelay<[Memo]> = BehaviorRelay.init(value: [])
}
struct Action {
let deleteMemo = PublishSubject<Memo>()
let changeMemo = PublishSubject<Memo>()
}
let state = State()
let action = Action()
private let bag = DisposeBag()
init() {
action.deleteMemo.subscribe(onNext: { memo in
print("delete \(memo)")
}).disposed(by: bag)
action.changeMemo.subscribe(onNext: { memo in
print("change \(memo)")
}).disposed(by: bag)
FirebaseManager.fetchAll()
.bind(to: state.memos)
.disposed(by: bag)
}
}
그리고 실행시켜보면, MemosViewController의 이 부분때문에
private var viewModel = MemosViewModel()
Firebase를 쓰기 전 가장 먼저 불려야하는 이 코드보다
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
return true
}
MemosViewModel 의 이니셜라이저 안에있는 FirebaseManager.fetchAll()이 먼저 실행되어서
크래쉬가 난다...! ( Firebase를 쓸 준비가 안되었는데 접근해서 그렇다...!!! )
그래서 코드를 이렇게 바꾸어주고
private var viewModel: MemosViewModel!
viewDidLoad에서 뷰모델을 생성해준다 그러면 Firebase.configure()이 먼저 실행되어서 크래쉬가 안난다..!
override func viewDidLoad() {
viewModel = MemosViewModel()
bindTableView()
tableView.rx.setDelegate(self).disposed(by: bag)
}
@IBOutlet weak var tableView: UITableView! {
didSet {
tableView.rx.setDelegate(self).disposed(by: bag)
bindTableView()
}
}
이렇게 tableView didSet에 해주었던 코드들도 viewModel이 생성된 다음에 실행되도록 같이 viewDidLoad에 옮겨주었다
bindTableView 메소드에 viewModel에 접근하는 코드가 들어가기 때문 --!
그리고 실행해보면 메모 데이터들을 받아오는 fetchAll 메소드가 항상 [] 의 옵져버블을 리턴한다는 문제가 발생한다
class func fetchAll() -> Observable<[Memo]> {
let rootRef = Database.database().reference()
rootRef.child("memos").observe(.value) { snapshot in
var memos: [Memo] = []
let memosDic = snapshot.value as? [String: Any] ?? [:]
for (key, _) in memosDic {
if let memoDic = memosDic[key] as? [String: Any], let memo = Memo(dic: memoDic) {
memos.append(memo)
}
}
}
return Observable.just(memos)
}
서버에 갔다가 온 후 리턴되야하는 코드인데 바로 리턴해버리면 항상 empty 배열만 리턴하기 때문이다
그럴때는 Observable.create 를 사용해주면 된다
class func fetchAll() -> Observable<[Memo]> {
return Observable<[Memo]>.create { observer in
let rootRef = Database.database().reference()
rootRef.child("memos").observe(.value) { snapshot in
var memos: [Memo] = []
let memosDic = snapshot.value as? [String: Any] ?? [:]
for (key, _) in memosDic {
if let memoDic = memosDic[key] as? [String: Any], let memo = Memo(dic: memoDic){
memos.append(memo)
}
}
observer.onNext(memos)
}
return Disposables.create()
}
}
이제 준비 끝 ---!! 실행해보면 fetch 가 잘된다
아이패드 시뮬레이터 하나 더 띄우고 큐브라떼 라는 메모를 저장해보면
바로바로 fetch가 된다
웹과 앱 모두 새로고침이나 reload하지 않아도 바로 데이터가 갱신되는데 신기하당 Firebase 짱-!
+ 데이터 fetch할 때 순서가 보장안되는 것은 딕셔너리로 변환하는 과정 때문이다 (딕셔너리는 unordered)
snapshot.value는 데이터를 순서대로 잘 준다
그래서 딕셔너리를 key에 따라서 sort해주는 코드를 추가한다
memosDic.sorted(by: {$0.key < $1.key})
fetchAll 메소드의 최종 코드는 이렇게 되겠당...!
class func fetchAll() -> Observable<[Memo]> {
return Observable<[Memo]>.create { observer in
let rootRef = Database.database().reference()
rootRef.child("memos").observe(.value) { snapshot in
var memos: [Memo] = []
let memosDic = snapshot.value as? [String: Any] ?? [:]
for (key, _) in memosDic.sorted(by: {$0.key < $1.key}) {
if let memoDic = memosDic[key] as? [String: Any], let memo = Memo(dic: memoDic){
memos.append(memo)
}
}
observer.onNext(memos)
}
return Disposables.create()
}
}
순서대로 잘 나온다 : )
observeSingleEvent / queryLimited 등 재밌는 기능들이 더 있지만 나중에 봐야지 🙃
'💻 > Firebase' 카테고리의 다른 글
[Firebase-DB] Firebase 예제 프로젝트(modify) - Realtime DB에서 데이터 변경하기 (0) | 2019.05.31 |
---|---|
[Firebase-DB] Firebase 예제 프로젝트(delete) - Realtime DB에서 데이터 삭제하기 (2) | 2019.05.28 |
[Firebase-DB] Firebase 예제 프로젝트(insert) - Realtime DB에 데이터추가 (0) | 2019.05.28 |
[Firebase] Firebase 예제 프로젝트(setup) - Firebase 설치하기 (0) | 2019.05.27 |
[Firebase] Firebase 예제 프로젝트 - 프로젝트 구성 (1) | 2019.05.27 |
- Total
- Today
- Yesterday
- DRF APIException
- Flutter Clipboard
- Sketch 누끼
- 구글 Geocoding API
- PencilKit
- drf custom error
- Dart Factory
- 장고 URL querystring
- flutter dynamic link
- SerializerMethodField
- Django Heroku Scheduler
- ribs
- github actions
- Django Firebase Cloud Messaging
- Flutter 로딩
- Flutter Text Gradient
- ipad multitasking
- Django FCM
- 장고 Custom Management Command
- METAL
- Python Type Hint
- Watch App for iOS App vs Watch App
- Flutter getter setter
- flutter 앱 출시
- Flutter Spacer
- cocoapod
- flutter deep link
- 플러터 얼럿
- flutter build mode
- 플러터 싱글톤
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |