Mac Wayne
Mac Wayne

Reputation: 597

Dictionary of custom objects, how best to sort and display in a SwiftUI view using List and ForEach?

I have a customObject which I store in Firebase's realtime database:

struct CustomObject: Codable {
    var id: UUID?
    var name: String?
    var status: String?
}

The customObjects are stored in a Dictionary with UUID being the key:

Firebase Dictionary Screenshot

I am able to load the data into a [String: CustomObject] Dictionary in my iOS application, but I am unsure if my approach to sort and display the customObjects using a List() ForEach(...) { is a best practice.

my current solution is to build an Array when the Dictionary is loaded

I use didSet everytime the database updates to recreate an Array which I can use on the list():

class AppManager: ObservableObject {

   @Published var customObjectArray: [CustomObject] = []

   @Published var customObjectDictionary: [String:CustomObject]? {
      didSet {
         if customObjectDictionary != nil {
            customObjectArray = []

            for (key, value) in customObjectDictionary! {
               var tempObject: CustomObject = value
               tempObject.id = UUID(uuidString: key)
               customObjectArray.append(tempObject)
            }

            customObjectArraySort()
         }
      }
   }
}

This is my View:

struct MainView: View {
    @EnvironmentObject var app: AppManager
    
    var body: some View {
        List {
            ForEach(app.customObjectArray.indices, id: \.self) { index in
                HStack{
                    Text(app.customObjectArray[index].name ?? "")
                    Spacer()
                    Text(app.customObjectArray[index].status ?? "")
                }
            }
        }
    }
}

I am aware that a Dictionary is a unordered collection and that attempting to sort based on customObject.name in a list with a Dictionary is unsuitable.

According to Apple's documentation

A dictionary stores associations between keys of the same type and values of the same type in a collection with no defined ordering. Each value is associated with a unique key, which acts as an identifier for that value within the dictionary. Unlike items in an array, items in a dictionary do not have a specified order. You use a dictionary when you need to look up values based on their identifier, in much the same way that a real-world dictionary is used to look up the definition for a particular word.

Is using didSet and making an Array from the Dictionary of customObjects considered a best practice?

Is there a better approach for sorting and listing customObjects from a Dictionary?

Upvotes: 1

Views: 843

Answers (1)

Yrb
Yrb

Reputation: 9665

Turning a Dictionary into a RandomAccessCollection, to which an Array conforms, is necessary if your want to run it through a ForEach, so this is fine.

Regardless of whether you have a Dictionary that you convert to an Array as your data source, you shouldn't use .indices in this way, especially for something that is easily made Identifiable.

struct MainView: View {
    @EnvironmentObject var app: AppManager
    
    var body: some View {
        List {
            ForEach(app.customObjectArray) { object in
                HStack{
                    Text(object.name ?? "")
                    Spacer()
                    Text(object.status ?? "")
                }
            }
        }
    }
}

struct CustomObject: Codable, Identifiable {
    var id: UUID // Make this non-optional
    var name: String?
    var status: String?
}

The way you set it up, if any element is added to, or removed from, the array, you can cause a crash. This means you can't use .onDelete, etc. Also, .onMove won't work properly either.

Upvotes: 1

Related Questions