You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Diffable DataSource增改删实现疑问及代码逻辑优化咨询

Hey there! Let's walk through your Diffable DataSource questions and code to get things sorted out. You're already off to a great start with the add/update functionality—let's refine this to align better with Diffable's design and tackle those open questions.

Key Improvements & Answers

1. Ditch manual array manipulation—use snapshots directly

Right now, you're pulling items from the current snapshot into an array, modifying that array, then passing it back to updateData. While this works, it skips a lot of Diffable DataSource's built-in efficiency. Instead, you should work directly with snapshots to modify your data state:

Here's how you can rewrite your save method to use snapshots properly:

func save(_ project: Project, withImage image: UIImage?) {
    var projectToBeSaved = project
    projectToBeSaved.lastEdited = Date()
    
    // Grab the current snapshot from the data source
    var currentSnapshot = dataSource.snapshot()
    
    if currentSnapshot.contains(projectToBeSaved) {
        // For existing projects: remove the old entry and add the updated one
        currentSnapshot.deleteItems([projectToBeSaved])
        currentSnapshot.appendItems([projectToBeSaved], toSection: .normal)
    } else {
        // For new projects: just append to the section
        currentSnapshot.appendItems([projectToBeSaved], toSection: .normal)
    }
    
    // Since snapshots don't support sorting directly, we'll create a new sorted snapshot
    let sortedItems = currentSnapshot.itemIdentifiers.sorted { $0.lastEdited > $1.lastEdited }
    var sortedSnapshot = NSDiffableDataSourceSnapshot<Section, Project>()
    sortedSnapshot.appendSections([.normal])
    sortedSnapshot.appendItems(sortedItems)
    
    // Apply the updated snapshot—no need for reloadData!
    dataSource.apply(sortedSnapshot, animatingDifferences: true)
    
    // TODO: Persist to JSON
}

A quick note: If your Project class properly implements Identifiable (with a stable, unique id property), you could also use currentSnapshot.reloadItems([projectToBeSaved]) to update existing entries instead of deleting/adding. But since you need sorting, rebuilding the sorted snapshot is the way to go.

2. Should you move all save logic to updateData?

Not exactly—but you can refactor to separate concerns for cleaner code. Instead of pulling items from the snapshot every time, maintain a single source of truth for your data (a projects array in your view controller). Then:

  • Let save handle modifying this array, sorting, and persistence
  • Let updateData handle turning that array into a snapshot and updating the UI

Here's what that refactored setup would look like:

class ProjectsViewController: UIViewController {
    // This is your single source of truth for project data
    private var projects: [Project] = []
    private var dataSource: UICollectionViewDiffableDataSource<Section, Project>!
    
    // Simplified updateData that uses your source-of-truth array
    func updateData() {
        var snapshot = NSDiffableDataSourceSnapshot<Section, Project>()
        snapshot.appendSections([.normal])
        snapshot.appendItems(projects)
        dataSource.apply(snapshot, animatingDifferences: true)
    }
    
    // ... rest of your view controller setup
}

extension ProjectsViewController: ProjectHandler {
    func save(_ project: Project, withImage image: UIImage?) {
        var projectToBeSaved = project
        projectToBeSaved.lastEdited = Date()
        
        // Update the source-of-truth array
        if let index = projects.firstIndex(of: projectToBeSaved) {
            projects[index] = projectToBeSaved
        } else {
            projects.append(projectToBeSaved)
        }
        
        // Sort the array
        projects.sort { $0.lastEdited > $1.lastEdited }
        
        // Persist to JSON (extract this to a helper method if you want!)
        saveProjectsToJSON()
        
        // Trigger UI update
        updateData()
        // REMOVE collectionView.reloadData() — apply() handles UI updates with animation!
    }
    
    private func saveProjectsToJSON() {
        // TODO: Implement your JSON persistence logic here
    }
}

This separation makes your code easier to debug and maintain—you always know exactly where your data is being modified and where the UI is being updated.

3. How to implement delete functionality

Following the source-of-truth pattern above, deleting is straightforward:

func deleteProject(_ project: Project) {
    // Remove from source-of-truth array
    projects.removeAll { $0.id == project.id }
    
    // Persist the change
    saveProjectsToJSON()
    
    // Update UI
    updateData()
    
    // Alternatively, if you want to work directly with snapshots (sync the array afterward!):
    // var snapshot = dataSource.snapshot()
    // snapshot.deleteItems([project])
    // dataSource.apply(snapshot)
    // projects = snapshot.itemIdentifiers
    // saveProjectsToJSON()
}

4. Quick critical fixes

  • Delete collectionView.reloadData(): Calling this negates all of Diffable DataSource's efficiency and animation benefits. The apply(snapshot) method already handles updating the UI properly.
  • Ensure Project is Identifiable: This is non-negotiable for Diffable to work correctly. Make sure your Project class has a unique, stable id property (like a UUID) so Diffable can track changes accurately.
  • Keep persistence separate: Extract your JSON saving logic to a helper method (like saveProjectsToJSON()) to keep your save method focused on business logic.

内容的提问来源于stack exchange,提问作者DeveloperSammy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 11:17:44