brunch

You can make anything
by writing

C.S.Lewis

by Tilltue Oct 16. 2016

Firebase #iOS, NewsFeed 기초

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 을 바꿔서 현재 보고있는 테이블의 이름이 변경되는지 확인해보자.



브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari