[swift] IGListDiffKit과 함께하는 전체 화면 구현

IGListDiffKit은 iOS 앱에서 데이터의 차이를 비교하고 업데이트하는데 도움을 주는 라이브러리입니다. 이번 포스트에서는 IGListDiffKit을 사용하여 전체 화면을 구현하는 방법에 대해 알아보겠습니다.

1. IGListDiffKit을 설치합니다.

먼저 IGListDiffKit을 프로젝트에 추가해야 합니다. CocoaPods를 사용한다면 Podfile에 다음과 같이 추가합니다.

pod 'IGListDiffKit'

그리고 pod install 명령어를 실행하여 IGListDiffKit을 설치합니다.

2. 데이터 모델과 컨트롤러를 생성합니다.

전체 화면을 구현하기 위해 필요한 데이터 모델과 컨트롤러를 생성합니다. 예를 들어, 사용자 목록을 표시하는 화면을 만든다고 가정해보겠습니다. 사용자 목록은 User라는 클래스로 표현되며, UsersViewController라는 컨트롤러에서 관리됩니다.

import UIKit

class User {
    let name: String
    let age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

class UsersViewController: UIViewController {
    private var users: [User] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        // 사용자 데이터를 가져온다
        fetchUsers()

        // 사용자 목록 화면을 구성한다
        setupCollectionView()
    }

    private func fetchUsers() {
        // 서버에서 사용자 데이터를 가져온다
        // 예시를 위해 더미 데이터를 사용하겠습니다
        users = [
            User(name: "John", age: 25),
            User(name: "Jane", age: 28),
            User(name: "Tom", age: 30)
        ]
    }

    private func setupCollectionView() {
        // 컬렉션 뷰를 생성하고 설정한다
        let layout = UICollectionViewFlowLayout()
        let collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
        collectionView.register(UserCell.self, forCellWithReuseIdentifier: "UserCell")
        collectionView.delegate = self
        collectionView.dataSource = self
        view.addSubview(collectionView)
    }
}

extension UsersViewController: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
    // 컬렉션 뷰 데이터 소스 및 델리게이트 메서드를 구현한다
    // ...
}

3. IGListDiffable 프로토콜을 채택합니다.

사용자 데이터 모델인 User 클래스가 IGListDiffable 프로토콜을 채택하도록 수정합니다. IGListDiffable 프로토콜은 IGListDiffKit에서 데이터 변경을 추적하고 업데이트하는 데 필요한 메서드를 정의합니다.

import IGListDiffKit

class User: NSObject, IGListDiffable {
    let name: String
    let age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }

    // IGListDiffable 프로토콜 메서드를 구현한다
    func diffIdentifier() -> NSObjectProtocol {
        return self
    }

    func isEqual(toDiffableObject object: IGListDiffable?) -> Bool {
        guard let user = object as? User else { return false }
        return name == user.name && age == user.age
    }
}

4. IGListKit을 사용하여 컬렉션 뷰 데이터 소스를 구현합니다.

IGListDiffKit과 IGListKit을 함께 사용하여 컬렉션 뷰 데이터 소스를 구현합니다. 이는 IGListKit의 IGListAdapterDataSource 프로토콜을 사용하여 IGListDiffKit과 연동하는 방식입니다.

import IGListKit

extension UsersViewController: IGListAdapterDataSource {
    func objects(for listAdapter: IGListAdapter) -> [IGListDiffable] {
        return users
    }

    func listAdapter(_ listAdapter: IGListAdapter, sectionControllerFor object: Any) -> IGListSectionController {
        return UserSectionController()
    }

    func emptyView(for listAdapter: IGListAdapter) -> UIView? {
        return nil
    }
}

5. 섹션 컨트롤러를 구현합니다.

UserSectionController라는 클래스를 생성하여 각 사용자를 표시하는 셀을 처리할 수 있도록 구현합니다.

import IGListKit

class UserSectionController: IGListSectionController {
    private var user: User?

    override init() {
        super.init()
        inset = UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0)
    }

    override func numberOfItems() -> Int {
        return 1
    }
    
    override func sizeForItem(at index: Int) -> CGSize {
        guard let width = collectionContext?.containerSize.width else { return .zero }
        return CGSize(width: width, height: 50)
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        guard let cell = collectionContext?.dequeueReusableCell(of: UserCell.self, for: self, at: index) as? UserCell,
              let user = user else {
            fatalError("Failed to dequeue cell or missing data")
        }
        cell.configure(with: user)
        return cell
    }

    override func didUpdate(to object: Any) {
        user = object as? User
    }
}

6. 셀을 구현합니다.

마지막으로 각 사용자를 표시하는 셀을 구현합니다. UserCell 클래스를 생성하고 configure(with:) 메서드를 추가하여 데이터를 업데이트할 수 있도록 합니다.

import UIKit

class UserCell: UICollectionViewCell {
    private let nameLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupViews()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupViews() {
        addSubview(nameLabel)
        // nameLabel의 제약 조건을 설정한다
    }

    func configure(with user: User) {
        nameLabel.text = user.name
    }
}

결론

IGListDiffKit을 사용하여 전체 화면을 구현하는 방법에 대해 알아보았습니다. IGListDiffKit은 데이터 차이를 비교하고 UI를 업데이트하는 작업을 간단하게 처리할 수 있도록 도와줍니다. IGListKit과 함께 사용하면 좀 더 효과적으로 화면을 구성할 수 있습니다. IGListDiffKit과 IGListKit 문서를 참조하면 더 자세한 정보를 얻을 수 있습니다.

참고 자료