TechnologiesSwiftUILists and Collections

ReorderDifference struct

iOSmacOStvOSwatchOSvisionOS✓ renders

The difference produced by a reordering operation.

How it works

A ReorderDifference captures the result of moving elements within an ordered collection: it records where items started and where they ended up after a reordering operation. SwiftUI produces this difference when a person drags a row to a new position in a list, giving you a structured description of the move rather than a raw before-and-after snapshot. Reach for it when you need to translate an interactive reorder gesture into a concrete mutation of your own data model, so the on-screen order and your stored order stay in agreement.

  1. Receive the move from onMove(perform:)

    Reordering begins when a row-presenting view reports that the user dragged content to a new slot. Attaching .onMove to the ForEach over items registers a handler that fires once the drag completes, handing you the difference as source (the offsets being moved) and destination (the target index).

  2. Read the source and destination offsets

    The reorder difference is expressed as a set of moved offsets and a single insertion point. In the closure, source is an IndexSet describing which positions were picked up and destination is the index they should land before, so together they fully describe the requested rearrangement without ambiguity.

  3. Apply the change to your model

    Applying the difference is what keeps your data authoritative. Calling items.move(fromOffsets: source, toOffset: destination) mutates the backing array to match the gesture; because items is @State, that mutation re-renders the List with the rows in their new order.

  4. Let people initiate reordering

    A reorder difference is only generated when the list is editable and the user can grab rows. Placing an EditButton() in the .toolbar toggles the list's edit mode, surfacing the drag handles that let onMove capture the move in the first place.

Try it — Replace the body of the .onMove closure with print("\(source) -> \(destination)") (omitting the items.move(...) call) and drag a row: the printed offsets show the reorder difference SwiftUI computed, while the rows snap back because nothing applied it to the model.

Example & preview

Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.

ReorderDifference.swift
struct ReorderDifferenceDemo: View {
    @State private var items = ["Apples", "Bread", "Milk", "Eggs"]

    var body: some View {
        NavigationView {
            List {
                ForEach(items, id: \.self) { item in
                    Text(item)
                }
                .onMove { source, destination in
                    items.move(fromOffsets: source, toOffset: destination)
                }
            }
            .navigationTitle("Groceries")
            .toolbar { EditButton() }
        }
    }
}
Live preview
Apples Bread Milk Eggs 9:41 Groceries
Apples Bread Milk Eggs 9:41 Groceries
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →