본문 바로가기
🍎 iOS

[iOS/RxSwift] RxSwift와 RxRealm으로 UICollectionView사용하기

by 틴디 2022. 9. 19.
728x90
반응형

Realm은 Object를 상속 받는 클래스를 타입으로 데이터 베이스에 저장된 객체들을 읽어 올 수 있습니다. 

private lazy var results = try! Realm().objects(Category.self)

keyPath에 전달된 필드값으로 내림차순, 오름차순 정렬을 해서 전달 받을 수 있습니다. id 를 기준으로 오름차순 해주면 아래처럼 작성해 주면 됩니다. 

var updates = try! Realm().objects(Category.self).sorted(byKeyPath: "id", ascending: true)

이렇게 적어 주어도 되고 전역 변수로 realm 객체를 따로 빼주어도 됩니다

let realm = try! Realm()
var updates = realm.objects(Category.self).sorted(byKeyPath: "id", ascending: true)

 

RxRealm을 전달해준 객체 타입의 변화를 체크해서 옵저빙 할 수 있습니다.

    private let layout: UICollectionViewFlowLayout = {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        return layout
    }()
    
    private lazy var categoryCollectionView: UICollectionView = {
        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        collectionView.contentInset = .init(top: 0, left: 16, bottom: 0, right: 16)
        collectionView.register(CategoryCollectionViewCell.self, forCellWithReuseIdentifier: "CategoryCollectionViewCell")
        return collectionView
    }()

우선 UICollectionViewFlowLayout과 UICollectionView를 생성해 줍니다. 

이제 위에서 생성해준 realm의 result 객체인 updates를 옵저빙 하도록 Observable을 생성해 줍니다. 

        Observable.array(from: updates)
            .bind(to: categoryCollectionView.rx.items(cellIdentifier: "CategoryCollectionViewCell", cellType: CategoryCollectionViewCell.self)) { index, category, cell in
                
            }.disposed(by: disposeBag)

RxCocoa를 이용해서 collectionView에 방출된 값을 바인딩 해주면 됩니다. 

collectionView.rx.items는 기존에 cellForItemAtIndexPath와 같은 역활을 하며 동작합니다. index와 Realm 데이터 베이스에서 넘어온 값, UICollectionViewCell에 대한 값이 넘어오므로 클로저 안에서 이를 활용할 수 있습니다. 

만약 UICollectionViewCell이 다양한 타입이라면 아래와 같이 사용하면 됩니다.

출처 : https://stackoverflow.com/questions/58940992/different-cells-collectionview-rxswift

let items = Observable.just([
             1,
             2,
             3
         ])

         items
         .bind(to: collectionView.rx.items) { (collectionView, row, element) in
            let indexPath = IndexPath(row: row, section: 0)
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! NumberCell
             cell.value?.text = "\(element) @ \(row)"
             return cell
         }
         .disposed(by: disposeBag)

 

델리게이트 설정 또한 RxCocoa에서 해줄 수 있습니다. dataSource를 따로 지정해 주지 않아도 됩니다. 

        categoryCollectionView.rx.setDelegate(self)
            .disposed(by: disposeBag)

 

셀이 선택되었을 때 이벤트를 받고 싶다면 rx.modelSelected를 사용하면 됩니다. 데이터 모델에 바로 접근이 가능해서 매우 편리

        categoryCollectionView.rx.modelSelected(Category.self)
            .map({ category in
                return category.id
            })
            .subscribe { id in
                print(id)
            }
            .disposed(by: disposeBag)

 

만약에 셀이 선택된 뒤 해당 셀의 데이터모델이 아닌 인덱스를 반환 받을 필요가 있다면 rx.itemSelected를 사용하면 됩니다.

        categoryCollectionView.rx.itemSelected
            .subscribe(onNext: { indexPath in
                
            }).disposed(by: disposeBag)

 

Pexels에서 Rafael Pires님의 사진: https://www.pexels.com/ko-kr/photo/1128229/

728x90
반응형

댓글