UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: Sorting an Array either before a ForEach or with a ForEach

Forums > SwiftUI

I have a roster that I would like to sort by active. I am struggling trying to see if the array should be sorted before the ForEach or using the ForEach.

Thank you!

Bob

//
//  ViewRoster.swift
//  NavigationViewExample
//
//  Created by ROBERT LAWSON on 6/5/22.
//

import SwiftUI

struct ViewRoster: View {
    @EnvironmentObject var roster: Roster
    var body: some View {
        NavigationView {
            List {
                if roster.students.isEmpty {
                    Text("Please add students")
                }else {
                    ForEach(roster.students) { student in
                        HStack {
                            HStack {
                                    Text(student.firstName)
                                        .font(.headline)
                                    Text(student.lastName)
                                        .font(.headline)
                                    Text(student.birthdate)
                                        .font(.caption)
                                    Text(student.selectedPeriod)
                                        .font(.caption)
                                    Text(student.emailAddress)
                                        .font(.caption)
                                    if student.isIEP {
                                        Text("IEP")
                                            .font(.caption)
                                    }
                                    if student.is504 {
                                        Text("504")
                                            .font(.caption)
                                    }
                                    if student.isELL {
                                        Text("ELL")
                                            .font(.caption)
                                    }
                                    if student.active {
                                        Text("Active")
                                    }
                                Spacer()
                                }
                        }
                        .swipeActions {
                            Button(role: .destructive) {
                                withAnimation {
                                    roster.delete(student)
                                }
                            } label: {
                                Label("Delete", systemImage: "trash")
                            }
                            Button {
                                withAnimation {
                                    roster.deactivate(student)
                                }
                            } label: {
                                Label("Deactivate", systemImage: "person.crop.circle.badge.xmark")
                            }
                            .tint(.blue)
                        }
                    }
                }
            } 
        }
        .navigationTitle("Active Student Roster")
        .navigationBarTitleDisplayMode(.inline) // Just added this
        .navigationViewStyle(.stack) // Makes the view full width
        .accentColor(.blue)
    }
}

struct ViewRoster_Previews: PreviewProvider {
    static var previews: some View {
        ViewRoster()
            .previewInterfaceOrientation(.landscapeLeft)
    }
}

2      

Robert asks for business logic advice:

I am struggling trying to see if the array should be sorted before the ForEach or using the ForEach.

Write yourself a note on a 3x5 index card and post it near your monitor. Write something like "SwiftUI is a declarative language!" Add emojis or smiley faces, what ever works. When you get stuck, refer to this note!

Think of ForEach as a view factory for a collection of objects. Try not to think of it as a traditional "for each" loop. What are you trying to build with the ForEach?

Answer: You are building an HStack of student views! Consider moving all your code to display a single student into its own StudentView.

// Authoritative Data source
@EnvironmentObject var roster: Roster

// ... snip ....
HStack {
    // ForEach is a view factory! You are building several views...
    ForEach(roster.students) {  student in
        StudentView(studentToDisplay: student)  // <-- You are building an HStack of StudentViews.
     }
 } // end of HStack
// ... more code here ...

Declare your intentions

Next, look at the index card. Ponder the declarative nature of SwiftUI. You're in charge! Tell the ForEach view builder that you are giving it a list of students, in order!

For this, you may have to go back to your original Roster object. This is the perfect place to create an ordered list to feed a ForEach view builder. Keep the sorting and selecting logic OUT of your views. Put the sorting and selecting logic INTO your authoritative data source.

In your Roster object, consider having several computed properties:

  1. allStudents
  2. yearSixStudents
  3. chorusStudents
  4. troubleMakers
    et cetera

You can embed the selection and the sorting logic within your Roster object. Keep the business of Rosters inside the Roster object. Also, keep the logic of selection (grab all yearSix students) apart from sorting (alphabetical, byAge, byHeight). Sorting and selecting are two different concepts.

Then building your views becomes a trivial matter of (checks index card) declaring(!) what you want to see in the view.

// Authoritative Data source
@EnvironmentObject var roster: Roster

// ... snip ....
HStack {
    // DECLARE what you want to see in these views.
    ForEach(roster.activeYearSixStudents) {  student in
        StudentView(studentToDisplay: student)  // <-- You are building an HStack of StudentViews.
     }

    // DECLARE what you want to see in these views.
    ForEach(roster.inactiveChorusStudents.sorted(by: .height) {  student in
        StudentView(studentToDisplay: student)  // <-- You are building an HStack of StudentViews.
     }
 } // end of HStack
// ... more code here ...

Hope this helps.

3      

It does! Thank you, I will begin reworking the roster and views today!

Bob

2      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.