swiftuikit

Is UITableViewDiffableDataSource not supporting nil?


In the following code example

import UIKit

struct Language: Hashable {
    let name: String
}

enum Section {
    case main
}

class ViewController: UIViewController, UITableViewDelegate {
    var tableView: UITableView!
    private typealias DataSource = UITableViewDiffableDataSource<Section, Language?>

    private var dataSource: DataSource!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Set up the table view
        tableView = UITableView(frame: view.bounds)
        view.addSubview(tableView)
        
        // Register a simple cell
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        
        // Set up the data source
        dataSource = DataSource(tableView: tableView) { tableView, indexPath, language in
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
            
            // Check if the language is nil and configure the cell accordingly
            if let language = language {
                cell.textLabel?.text = language.name
            } else {
                cell.textLabel?.text = "No Language"
            }
            return cell
        }
        
        // Set up the snapshot with some sample data including nil
        var snapshot = NSDiffableDataSourceSnapshot<Section, Language?>()
        snapshot.appendSections([.main])
        snapshot.appendItems([Language(name: "English"), nil, Language(name: "Spanish"), Language(name: "French")])
        
        // Apply the snapshot to the data source
        dataSource.apply(snapshot, animatingDifferences: true)
        
        tableView.delegate = self
    }
}

I am getting runtime error

Could not cast value of type 'NSNull' (0x1ec78e900) to 'xxx.Language' (0x1008e0468).

Is UITableViewDiffableDataSource not supporting nil? I can't find https://developer.apple.com/documentation/uikit/uitableviewdiffabledatasource talks about this limitation.

Thanks.


Solution

  • The documentation for NSDiffableDataSourceSnapshot states:

    Important

    Each of your sections and items must have unique identifiers that conform to the Hashable protocol.

    nil cannot satisfy this requirement.

    Because UITableView is Objective-C, the nil has been translated to the special singleton NSNull which also cannot satisfy this requirement. NSNull also cannot be converted to an instance of Language, which is the error you are getting.

    While the documentation doesn't explicitly state that you can't add nil, the requirement for items to have unique identifiers strongly implies this.

    In fact, using an optional as your item type is the error that should be flagged. This doesn't make sense. Your snapshot is the items that exist. If an item doesn't exist you simply don't add it to the snapshot

    While the reason for the error you get many not be immediately obvious and it would be better for your error of declaring an optional type as your item type to be flagged at compile time, the behaviour seems reasonable in the circumstances.