Inspector of multiple-object selection in SwiftUI

This is rather a convoluted problem, maybe a starter of a discussion for an application pattern.

I am trying to create an application for editing dynamic objects (structure can not be expressed as a struct/class - therefore it is not known to the application developer), which can be simulated using a dictionary for now. There might be multiple collections (or filters) of such objects. In each collection an user can select one or multiple of the objects and inspect them using a third view: an inspector. Inspector can inspect and set properties of one or more objects.

The distilled application idea with some concept mockups and more detailed information is here at Github.

WARNING: The application DOES NOT WORK as intended, it is just there to demonstrate some issues.

It might look a bit convoluted, but can not think of a simpler solution for given problem. Tried to extract the essentials.

Either I have deep misunderstanding of SwiftUI (knowledge comes mostly from official docs), or there is something obscure going on.

The application views are as follows:

 Window
   |
   +-- Content View (*>)
         |
         +-- Navigation View
         |     |
         |     +-- [sidebar] List of Thing Filters
         |     |
         |     +-- ThingListView(<*) – list of things, selectable, multiple
         |
         +-- Inspector(<*) – of selection in the above
 
 
 (*>) Selection – state, source of truth
 (<*) Selection - binding to

"Visual" representation:

          Navigation         Inspector
 |<----------------------->|<--------->|

 +----------+--------------+-----------+
 | Filter 1 |**Thing 1*****| Selected: |
 | Filter 2 |  Thing 2     |  1,3      |
 | ....     |**Thing 3*****|           |
 |          | ...          | Name: ___ |
 +----------+--------------+-----------+
                 ^
                 |
                 +------- this can be 2D canvas, can be anything to present
                          a collection of selectable objects.

Note: The ThingListView might as well be some kind of Canvas, or any other view, it does not have to be just a list view.

Issue 1

I am experiencing an issue where the binding set is called on no change in any of the the Inspector subviews. This has a negative side-effect on the model.

  1. Pick a Filter (Thing collection)
  2. Select multiple (more than one) items
  3. One of (any):
    • Change selection to one item
    • Switch to another Filter

Result: All previously selected items will be changed.

Expected: No change happens.

What happened: set of a binding (see below) to a text filed is called on selection change, not on text field content change.

The offending code location: Inspector.swift -> class Inspector -> var body -> nameBinding -> set. For the context the simplified listing is here. Note the name and nameBinding are just mockups, there might be more properties as well as different kinds of inspectors.

struct Inspector: View {
    @State var name: String = ""
    // ... more state is defined here ...

    var body: some View {
        let nameBinding = Binding<String>(

            get: {
                // get one or coalesce multiple values of a dynamic property `name`
            },

            set: { text in
                // set the property in all selected objects
            }
        )
        // ... view definition continues here
    }
}

Issue 2

This is minor, but noticed that the get of the binding is called very frequently.

Question

How to make SwitfUI to call set of a binding only when the value actually changed?

Alternatively: if I did not get the solution approach right, what is the more paradigmatic way of solving the

(Collections → Things) → Inspector

application flow when the objects have dynamic properties (can not be expressed as structs/classes known to the application developer) and one can inspect a multi-object selection?

  • If you are using MVVM, can you say a bit more about your ViewModel?

  • I gave up, moved to AppKit. This question is no longer relevant.

Add a Comment