Sample CodemacOSReviewed 2026-07-21View on Apple Developer

Supporting Collection View Drag and Drop Through File Promises

At a glance

Item Summary
Purpose Load photos into a collection view, reorder them, import external files/promises, and export promised files.
Architecture A controller owns collection state and operation queues; PhotoItem owns per-photo loading state; delegate extensions implement drag/drop and file-promise contracts.
Collection model NSCollectionViewDiffableDataSource and snapshots are the displayed ordering source.

Project structure

CollectionViewDragDrop/
├── ViewController.swift
├── ViewController+DragAndDrop.swift
├── PhotoItem.swift
├── LoadPhotosOperation.swift
├── LoadThumbnailOperation.swift
├── PromiseFileProvider.swift
└── CollectionViewItem.swift

The controller’s normal collection setup and its large drag/drop protocol surface are separated into two files.

Overall architecture

Reference code

CollectionViewDragDrop/ViewController.swift:83 — background discovery is converted to main-thread collection state in one place.

    func loadPhotos() {
        // ...
    }

Ownership and state

Ownership evidence

CollectionViewDragDrop/ViewController.swift:20 — separate queues express separate work ownership.

var loaderQueue = OperationQueue()

var filePromiseQueue: OperationQueue = {
    let queue = OperationQueue()
    return queue
}()

The view controller owns ordering, destination URL, progress UI, and promise I/O. The diffable data source retains displayed PhotoItem objects. Each item guards its own thumbnail load and weakly notifies the controller when derived display state is ready.

Class and protocol design

Type Responsibility
ViewController Collection composition, diffable state, queues, and thumbnail updates.
ViewController drag/drop extension Collection delegate plus NSFilePromiseProviderDelegate.
PhotoItem File URL, title, image state, and lazy thumbnail request.
LoadPhotosOperation / LoadThumbnailOperation Background discovery and image derivation.
FilePromiseProvider Add internal drag identity and file URL pasteboard representations.
ThumbnailDelegate Notify one observer that derived state changed.

Access control

Boundary Effect and rationale
private imageLoading Prevents overlapping thumbnail operations for one model object.
private createLayout and data-source factories Keeps collection composition behind the controller.
weak thumbnailDelegate Avoids a photo retaining the controller/data-source owner.
public override writingOptions Preserves the superclass override’s visible contract; the internal subclass still caps external construction.
Other declarations are implicit internal Cross-file delegate extensions can collaborate inside the app target.

CollectionViewDragDrop/PhotoItem.swift:26 and CollectionViewDragDrop/PromiseFileProvider.swift:61 show these two distinct boundaries.

Logic ownership and placement

Logic Owner
Collection layout and snapshot application ViewController
Drop validation, import, reorder, and export ViewController+DragAndDrop
Pasteboard representation details FilePromiseProvider
File enumeration and thumbnail generation Operation subclasses
Duplicate-load prevention PhotoItem

Design patterns

Pattern Evidence Purpose
MVC CollectionViewDragDrop/PhotoItem.swift:20, CollectionViewDragDrop/ViewController.swift:14 Separates photo state from AppKit coordination.
Operation CollectionViewDragDrop/LoadPhotosOperation.swift:11 Moves filesystem/image work off the main thread.
Delegate CollectionViewDragDrop/PhotoItem.swift:16 Reports thumbnail completion without model-to-view coupling.
File promise CollectionViewDragDrop/ViewController+DragAndDrop.swift:374 Defers file creation/copy until the drop destination requests it.
Diffable data source CollectionViewDragDrop/ViewController.swift:39 Makes the snapshot the collection ordering model.

Naming conventions

  • Operations use verb-object names: LoadPhotosOperation and LoadThumbnailOperation.
  • The framework adapter is named by its superclass role: FilePromiseProvider.
  • ViewController+DragAndDrop clearly marks a capability extension, while PhotoItem names the displayed model.

Architecture takeaways

  • Separate discovery work, thumbnail work, and promise I/O with explicit queues.
  • Keep the collection ordering source authoritative during reordering.
  • Put pasteboard encoding in the provider and drop policy in the controller delegate.
  • Use weak model-to-controller callbacks for derived display updates.

Source map

Source Role
CollectionViewDragDrop/ViewController.swift:14 Collection owner
CollectionViewDragDrop/ViewController+DragAndDrop.swift:13 Drag/drop adapter
CollectionViewDragDrop/PhotoItem.swift:20 Photo model and thumbnail state
CollectionViewDragDrop/PromiseFileProvider.swift:10 Pasteboard provider