iosswiftdiffabledatasource

how to resolve DiffableDataSource mulipleCell crash (iOS 13)


I encountered an error during development. The minimum target is iOS 13. You want to give different cells for each section using DiffableDataSource. I don't know why there's an error. I need your help.

minumum target: iOS 13.0 *

🚨 errorCode 🚨

Thread 1: "unable to dequeue a cell with identifier MuseumItemCell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard"

don't used Storyboard, only programming UI

-- ✅ CODE ✅ --


import UIKit
import SnapKit

final class MuseumViewController: UIViewController {
    
    enum Item: Hashable {
        case bannerItem([String])
        case numberItem([Int])
    }
    
    enum MySection: Int {
        case banner
        case number
    }
    
    
    var tableView = UITableView()
    var dataSource: UITableViewDiffableDataSource<MySection, Item>!
    var banners: [String] {
        [
            "ABCDEFGHIJKL",
            "ABCDE",
            "A",
        ]
    }
    var numbers: [Int] = [100000, 10000, 1000, 100, 10, 10]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        setupTableView()
        
        fetchDataSource()
        fetchSnapShot()
    }
    
    func setupTableView() {
        view.addSubview(tableView)
        
        tableView.register(MuseumBannerCell.self, forCellReuseIdentifier: MuseumBannerCell.identifier)
        tableView.register(MuseumNumberCell.self, forCellReuseIdentifier: MuseumNumberCell.identifier)
        
        tableView.snp.makeConstraints {
            $0.edges.equalToSuperview()
        }
    }
    
    func fetchSnapShot() {
        var snapshot = NSDiffableDataSourceSnapshot<MySection, Item>()
        snapshot.appendSections([.banner, .number])
        snapshot.appendItems([.bannerItem(banners), .numberItem(numbers)])
        dataSource.apply(snapshot)
    }
    
    func fetchDataSource() {
        dataSource = UITableViewDiffableDataSource<MySection, Item>(
            tableView: tableView
        ) { tableView, indexPath, itemIdentifier in
            
            let section = MySection(rawValue: indexPath.section)
            
            switch section {
            case .banner:
                guard let cell = tableView.dequeueReusableCell(
                    withIdentifier: MuseumBannerCell.id,
                    for: indexPath
                ) as? MuseumBannerCell else { return UITableViewCell() }
                
                cell.backgroundColor = .red
                
                return cell
                
            case .number:
                guard let cell = tableView.dequeueReusableCell(
                    withIdentifier: MuseumNumberCell.id,
                    for: indexPath
                ) as? MuseumNumberCell else { return UITableViewCell() }
                
                cell.backgroundColor = .blue
                
                return cell
            default:
                return UITableViewCell()
            }
        }
        
    }
}


class MuseumBannerCell: UITableViewCell {
    static let id: String = "MuseumBannerCell"
    
    // MARK: - Initialize
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}


class MuseumNumberCell: UITableViewCell {
    static let id: String = "MuseumItemCell"
    
    // MARK: - Initialize
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}


Solution

  • In your setupTableView method you set

    tableView.register(MuseumBannerCell.self, forCellReuseIdentifier: MuseumBannerCell.identifier)
    tableView.register(MuseumNumberCell.self, forCellReuseIdentifier: MuseumNumberCell.identifier)
    

    and later you call

    tableView.dequeueReusableCell(withIdentifier: MuseumBannerCell.id, for: indexPath)
    

    Try to register the cells with MuseumBannerCell.id (and MuseumNumberCell.id) since that's the same identifier you use for dequeuing.

    tableView.register(MuseumBannerCell.self, forCellReuseIdentifier: MuseumBannerCell.id)
    tableView.register(MuseumNumberCell.self, forCellReuseIdentifier: MuseumNumberCell.id)