ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • UITableViewDiffableDataSource, NSDiffableDataSourceSnapshot 사용해보기
    swift 2024. 1. 17. 00:16

    안녕하세요. 

     

    이제 저희 회사의 ios min version이 드디어 ios13이 되었네요...

     

    그래서 드디어 UITableViewDiffableDataSource를 사용할 수 있게 되었습니다.

     

    일단 예제를 설명하기 전에 문서부터 봐볼게요 :)

    Diffable 데이터 소스 객체는 테이블 뷰 객체와 함께 작동하는 특수한 유형의 데이터 소스입니다.

    이는 테이블 뷰의 데이터와 UI를 간단하고 효율적으로 관리하는 데 필요한 동작을 제공합니다.

    또한 UITableViewDataSource 프로토콜을 준수하며 프로토콜의 모든 메서드에 대한 구현을 제공합니다.

     

    이렇게 나와 있는데요.

     

    바로 예제로 보시죠 ㅎㅎ

     

     

    섹션, 아이템 만들기

    먼저 TableView를 만들어 주기 위해서는 section이 필요합니다.

     

    섹션 생성

    SectionIdentifierType : Hashable, SectionIdentifierType : Sendable,

    위 코드를 보아하나 섹션은 Hashable, Sendable를 채탹하고 있어야 된다고 하네요. 

     

    enum Section {

        case feed, post, board

    }

     

    기본 타입은 Hashable로 되어 있다고 합니다. 

    enum Type도 마찬가지 입니다. (다만, enum 타입에 associated value가 존재 한다면 func hash(into hasher: inout Hasher) 매서드를 정의를 해줘야 된다고 하네요.)

     

    아이템 생성

    ItemIdentifierType> : NSObject, ItemIdentifierType : Hashable, ItemIdentifierType : Sendable

     

    item 또한 Hashable을 채택하고 있어야 된다고 하네요.

     

    struct Feed: Hashable {

     

        let uuid: UUID = UUID()

        var content: String

        

        init(content: String) {

            self.content = content

        }

    }

    struct으로 모델을 정의하면 hash 함수를 정의하지 않아도 됩니다.

    [ struct는 Swift에서 기본 제공하는 타입입니다. 이는 이미 Hashable 프로토콜을 준수하도록 설계되어 있습니다. 따라서 struct를 사용하면 별도로 hash 함수를 정의하지 않아도 됩니다. 특히, struct의 모든 프로퍼티가 Hashable을 준수하는 경우, Swift는 자동으로 hash 함수를 생성합니다. 이 경우, 'Feed' struct의 모든 프로퍼티 'uuid'와 'content'가 Hashable을 준수하기 때문에 별도로 hash 함수를 정의할 필요가 없습니다. ]

     

    1. dataSource를 tableView에 연결 합니다.

    2. cell Provider에서 tableView에 보여줄 cell을 구성합니다.

    3. 현재의 상태의 데이터를 생성합니다.

    4. Data를 화면에 보여지도록 합니다.

     

     

     

    만약 class로 모델을 정의 한다면 아래 사진과 같이 Equatable, Hashable을 채택하라는 오류가 나옵니다.

    [이 오류는 class가 기본적으로 Hashable 혹은 Equatable 프로토콜을 준수하지 않기 때문에 발생합니다. 따라서, class를 사용하여 모델을 정의하려면 이 프로토콜들을 명시적으로 채택하고 구현해야 합니다. 이는 Diffable Data Source에서 데이터의 고유성과 동등성을 판단하기 위해 필요합니다.]

     

    그래서 저는 

     

    class Feed: Hashable {

     

        let uuid: UUID = UUID()

        var content: String

        

        init(content: String) {

            self.content = content

        }

        

        func hash(into hasher: inout Hasher) {

            hasher.combine(uuid)

        }

        

        static func == (lhs: Feed, rhs: Feed) -> Bool {

            lhs.uuid == rhs.uuid

        }

    }

     

    이렇게 모델을 정의 하였습니다.

     

     

    DataSource 생성, 테이블뷰에 DataSource 연결하기

        typealias DataSource = UITableViewDiffableDataSource<Section, Feed>

     

        //MARK: PROPERTY

        var dataSource: DataSource!

     

            dataSource = UITableViewDiffableDataSource(tableView: tableView, cellProvider: { tableView, indexPath, item in

                let cell = UITableViewCell()

                cell.textLabel?.text = item.content

                return cell

            })

            

            tableView.dataSource = dataSource

     

    dataSource를 만들어서 dataSource에 넣어주고 tableView에 dataSource를 알려줍니다.

     

     

    이제 dataSource에 어떤 데이터를 보여줄 보여줄 것인지만 알려주면 되겠죠?

     

     

    테이블뷰에 데이터 바인딩

    Then, you generate the current state of the data and display the data in the UI by constructing and applying a snapshot. For more information, see NSDiffableDataSourceSnapshot.

     

    NSDiffableDataSourceSnapshot 이 친구를 사용해서 테이블뷰에 보여줄 데이터를 구성할 예정이에요. 

    Diffable data sources에서는 테이블뷰 또는 컬렉션뷰에 데이터를 제공하기 위해 이 snapShots을 사용한다고 합니다.

    그리고 변경된 점들을 반영하기 위해도 사용된다고 하네요.

     

    NSDiffableDataSourceSnapshot를 만들어 줄 때 마다 너무 기니까 

    typealias SnapShot = NSDiffableDataSourceSnapshot<Section, Feed> 이런식으로 정의를 해볼게요.

     

     var feedList: [Feed] = [

            Feed(content: "첫 번째 피드의 내용입니다."),

            Feed(content: "두 번째 피드의 내용입니다."),

            Feed(content: "세 번째 피드의 내용입니다."),

            Feed(content: "네 번째 피드의 내용입니다."),

            Feed(content: "다섯 번째 피드의 내용입니다.")

     ]

        

      var snapShot = SnapShot()

      snapShot.appendSections([.feed])

      snapShot.appendItems(feedList)

     

      dataSource.apply(snapShot, animatingDifferences: true)

     

     

    snapShot을 생성하고 보여줄 section, itemType을 전달해주면 됩니다. 

    (단, section이 없으면 런타임 오류가 납니다. 꼭 넣어주세요.)

    그리고 apply를 호출해야 cellProvider이 호출되어 변경사항이 적용될거에요. 

     

    꼭 잊지 마시고 apply를 하시길 바랍니다.

     

    아래는 전체 코드 입니다. 

     

    작은 도움이라도 되었으면 좋겠습니다 :)

     

    읽어주셔서 감사합니다. 

     

     

Designed by Tistory.