firebase, realtime database, timeline
* 이글은 Swift 3.0 , Firebase 3.6.0 를 기준으로 작성되었습니다.
firebase 실시간 데이터 베이스를 뉴스피드형태로 사용하는 간단한 예제를 만들어 보려 한다.
1. 실시간으로 추가되는 데이터를 업데이트 해준다.
2. 새로고침으로 새로운 데이터를 가져온다.
3. 더 가져오기를 통해 오래된 데이터를 불러온다.
1,2 번의 경우 firebase 의 데이터베이스 이벤트를 활용하면 된다.
( childAdded,childChanged )
https://brunch.co.kr/@tilltue/19
보통 feed 의 경우 날짜를 기준으로 데이터를 가져와야 하지만, 적절한 예제json 이 없어서
이 글에서 사용한 프로젝트를 활용하려 한다.
날짜 대신에 기본 key 값으로 활용하려 한다.
테이블 refresh, load more 를 UI로 표현해줄 오픈소스를 하나 추가한다.
pod 'PullToRefresher', '~> 2.0'
https://github.com/Yalantis/PullToRefresh
ViewController 에 아래의 코드를 추가하자.
import PullToRefresh
...
class ViewController: UIViewController {
@IBOutlet fileprivate weak var tableView: UITableView!
var ref: FIRDatabaseReference? = nil
var cards = [Card]()
let refresher = PullToRefresh()
deinit {
tableView.removePullToRefresh(tableView.bottomPullToRefresh!)
tableView.removePullToRefresh(tableView.topPullToRefresh!)
}
override func viewDidLoad() {
super.viewDidLoad()
//... 초기 데이터 15개를 불러오는 코드
self.ref = FIRDatabase.database().reference()
guard let ref = self.ref else { return }
let query = ref.child("Cards").queryLimited(toFirst: 15)
query.observeSingleEvent(of: .value, with: { [weak self] snapshot in
guard let wself = self else { return }
print(snapshot.value)
for childSnapshot in snapshot.children {
if let childSnapshot = childSnapshot as? FIRDataSnapshot {
let card = Card(snapshot: childSnapshot)
wself.cards.append(card)
}
}
wself.tableView.reloadData()
})
removeEventHandler(ref: ref)
setupPullToRefresh()
}
}
fileprivate extension ViewController {
func moreLoading() {
if let ref = self.ref, let lastCard = cards.last {
let key = String((Int(lastCard.ref.key) ?? 0) + 1)
let query = ref.child("Cards").queryOrderedByKey().queryStarting(atValue: key).queryLimited(toFirst: 3)
query.observeSingleEvent(of: .value, with: { [weak self] snapshot in
guard let wself = self else { return }
for childSnapshot in snapshot.children {
if let childSnapshot = childSnapshot as? FIRDataSnapshot {
let card = Card(snapshot: childSnapshot)
wself.cards.append(card)
}
}
wself.tableView.reloadData()
wself.tableView.endRefreshing(at: .bottom)
})
}else{
//Failed
self.tableView.endRefreshing(at: .bottom)
}
}
현재 가진 카드 객체중 마지막 객체의 키값에 1을 더해서 그때부터 데이터를 3개 더 가져오는 코드이다.
let key = String((Int(lastCard.ref.key) ?? 0) + 1)
let query = ref.child("Cards").queryOrderedByKey().queryStarting(atValue: key).queryLimited(toFirst: 3)
하단 refresh 시 moreloading 함수를 호출하도록 하자.
func setupPullToRefresh() {
tableView.addPullToRefresh(PullToRefresh()) { [weak self] in
let delayTime = DispatchTime.now() + Double(Int64(2 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
DispatchQueue.main.asyncAfter(deadline: delayTime) {
}
}
tableView.addPullToRefresh(PullToRefresh(position: .bottom)) { [weak self] in
let delayTime = DispatchTime.now() + Double(Int64(2 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
DispatchQueue.main.asyncAfter(deadline: delayTime) {
self?.moreLoading()
}
}
}
}
위와 같이 3개씩 다음 아이템을 불러오는 것을 확인 할 수 있다.
업데이트 될때를 위한 코드를 작성해보자.
func changeEventHandler(ref: FIRDatabaseReference){
_ = ref.child("Cards").observe(.childChanged, with: { [weak self] snapshot in
print("change!!")
print(snapshot.value)
guard let wself = self else { return }
let card = Card(snapshot: snapshot)
if let updateIndex = wself.cards.index(of: card) {
wself.tableView.beginUpdates()
wself.cards[updateIndex] = card
wself.tableView.reloadRows(at: [IndexPath(row: updateIndex, section: 0)], with: .none)
wself.tableView.endUpdates()
}
})
}
콘솔에서 카드 내의 name 을 바꿔서 현재 보고있는 테이블의 이름이 변경되는지 확인해보자.