How to save the ".onMove" rearrangement of the list in this code so it won't revert back to the original upon quit?

I tried numerous CoreData tutorials and they didn't work as those tutorials all focused on user-inputted lists with different Foundation files

Code:

//
//  ContentView.swift
//  PhysCal
//
//  Created by David Empire on 12/16/22.
//

import SwiftUI

struct ContentView: View {
    @State private var formulas: [ (name: String, destination: AnyView) ] = [
        (name: "Unit Conversions", destination: AnyView(UnitConversion())),
        (name: "Force", destination: AnyView(Force())),
        (name: "Work", destination: AnyView(Work())),
        (name: "Tension", destination: AnyView(Tension())),
        (name: "Displacement", destination: AnyView(Displacement())),
        (name: "Acceleration", destination: AnyView(Acceleration())),
        (name: "Angular Speed", destination: AnyView(AngularSpeed())),
        (name: "Projectile Motion", destination: AnyView(ProjectileMotion())),
        (name: "Moment", destination: AnyView(Moment())),
        (name: "Momentum", destination: AnyView(Momentum())),
        (name: "Surface Charge Density", destination: AnyView(SurfaceChargeDensity())),
        (name: "Position After Time", destination: AnyView(PositionAfterTime())),
        (name: "Spring Constant", destination: AnyView(SpringConstant())),
        (name: "Weight", destination: AnyView(Weight())),
        (name: "Heat of Fusion", destination: AnyView(HeatofFusion())),
        (name: "Wavelength and Frequency", destination: AnyView(Wavelength_Frequency())),
        (name: "Torque", destination: AnyView(Torque())),
        (name: "Kinetic Energy", destination: AnyView(KineticEnergy())),
        (name: "Gravitational Potential Energy", destination: AnyView(Gravitational_Potential_Energy())),
        (name: "Centripetal Force", destination: AnyView(CentripetalForce())),
        (name: "Centripetal Acceleration", destination: AnyView(CentripetalAcceleration())),
        (name: "Period", destination: AnyView(Period())),
        (name: "Frequency", destination: AnyView(Frequency())),
        (name: "Power", destination: AnyView(Power())),
        (name: "Speed of Sound", destination: AnyView(SpeedOfSound())),
        (name: "Normal Force on Inclined Plane", destination: AnyView(NormalForceOnInclinedPlane())),
        (name: "Friction", destination: AnyView(Friction())),
        (name: "Horsepower", destination: AnyView(Horsepower()))
    ]

    
    @State private var searchText = ""
    
    var body: some View {
        NavigationView {
            List {
                Section {
                    ForEach(searchResults, id: \.name) { formula in
                        NavigationLink (formula.name, destination: formula.destination)
                    }
                    
                    .onMove { indices, newOffset in
                        formulas.move(
                            fromOffsets: indices,
                            toOffset: newOffset
                        )
                    }
                        
                } header: {
                    Text("Formulas")
                }
            }
            .navigationTitle("PhysCal")
            .searchable(text: $searchText, placement: .sidebar)
            .listStyle(SidebarListStyle())
            .frame(minWidth: 225)
            VStack {
                Text("No Formula Selected").fontWeight(.bold)
                    .font(.system(size: 24))
                    .foregroundColor(Color.gray)
                    .multilineTextAlignment(.center)
            }
        }
        .toolbar {
            ToolbarItem(placement: .navigation) {
                Button(action: toggleSidebar, label: { // 1
                    Image(systemName: "sidebar.leading")
                })
            }
        }
    }
    
    var searchResults: [ (name: String, destination: AnyView) ] {
        if searchText.isEmpty {
            return formulas
        } else {
            return formulas.filter { $0.name.localizedCaseInsensitiveContains(searchText) }
        }
    }
    
    private func toggleSidebar() { // 2
    #if os(iOS)
    #else
    NSApp.keyWindow?.firstResponder?.tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)), with: nil)
    #endif
    }
}

hi,

i would first change the definition of your formulas array into a fixed dictionary to look up a navigation destination based on a string; so something like

let formula: [ String : AnyView ] = [
  "Unit Conversions" : AnyView(UnitConversion()),
  // and everything else ...
  ]

and with this in place, your ContentView would have:

@State private var names: [String] = [ "Unit Conversions", /* everything else */ ]

// most other stuff as before, except change the ForEach to iterate over the names array

ForEach(names) { name in
  NavigationLink (name, destination: formula[name]!)
}

this gets you to the point that you only need to save the array of strings for formula names. you will have to change the .onMove modifier now to move positions in the names array.

now it's easy to save/restore the names array to retain order. Core Data seems like overkill for this (unless you already use Core Data in your app elsewhere), so i would suggest the simplest option: keep the array formula names in AppStorage and replace the @State property wrapper with @AppStorage.

hope that helps,

DMG

How to save the ".onMove" rearrangement of the list in this code so it won't revert back to the original upon quit?
 
 
Q