skip to Main Content

I have a ForEach that I use to display some info, sorted on it’s date attribute:

My view looks like:

ForEach(records.sorted(by: < ), id: .self) { record in
                Text("(record.date")
            }
            .onDelete(perform: deleteRecord)

Record.swift

class Record : Comparable {
    
    var value: Float
    var date: Date
    
    
    init(value: Float = 0.0, date: Date = Date.now) {
        self.value = value
        self.date = date
    }
    
    static func < (lhs: Record, rhs: Record) -> Bool {
        return lhs.date < rhs.date
    }
    
}

My problem is that whenever I delete an item, the wrong one is actually removed.

deleteRecord()

func deleteRecord(_ indexSet: IndexSet) {
        for index in indexSet {
            movement.records.remove(at: index)
        }
    }

I’v tried changing the deleteRecord() method to something like:

func deleteRecord(at offsets: IndexSet) {
        movement.records.remove(atOffsets: offsets)
    }

but this did not solved my issue.

3

Answers


  1. Chosen as BEST ANSWER

    I managed to make a simple solution:

    First I sorted the ForEach like this:

        ForEach(records.sorted(by: {$0.date < $1.date}), id:  .self) { record in
                Text("(record.date)")      
            }
            .onDelete(perform: deleteRecord)
    

    After that, in deleteRecord():

            func deleteRecord(_ indexSet: IndexSet) {
            
            // Sorting the data before it's in the view
            var tmpSortedData = records.sorted(by: {$0.date < $1.date})
             
            // Removing the item
             for index in indexSet {
                 tmpSortedData.remove(at: index)
             }
             
            // Updating data model
            records = tmpSortedData
        
        }
    

  2. You can sort the record array not on the ForEach but after you add the records.

    Remove the .sorted(by: < ) from the ForEach and add it to the end of the data fetching. And it should work like a charm.

    Warning: You should create a temporary array, sort the temporary array and then save it to records so it doesn’t do some weird moving animations.

    Tip: You should use structs instead of classes. Because classes are reference type and structs are value type.
    More info about it here: Value And Reference Types In Swift

    Login or Signup to reply.
  3. Problem

    The index of your sorted array and the original index of the records data are different. That’s why you are removing wrong item.

    Solution

    You can make a conversion of your sorted item index to the original index in your delete function. I’m sharing the demo code:

    class Record: Equatable {
        var value: Float
        var date: Date
        
        
        init(value: Float = 0.0, date: Date = Date.now) {
            self.value = value
            self.date = date
        }
        
        static func == (lhs: Record, rhs: Record) -> Bool {
            return lhs.value == rhs.value
        }
        
        static func < (lhs: Record, rhs: Record) -> Bool {
            return lhs.value < rhs.value
        }
    }
    
    struct ContentView: View {
        @State private var records: [Record] = [.init(value: 4, date: .now), .init(value: 2, date: .now), .init(value: 3, date: .now)]
        
        private var sortedRecords: [Record] {
            records.sorted(by: <)
        }
        
        var body: some View {
            List {
                ForEach(sortedRecords, id: .value) { record in
                    Text("Value: (record.value)")
                }
                .onDelete(perform: deleteRecord)
            }
        }
        
        func deleteRecord(_ indexSet: IndexSet) {
            for index in indexSet {
                let recordToRemove = sortedRecords[index]
                guard let indexToDelete = records.firstIndex(of: recordToRemove) else { return } // --> Here it is
                records.remove(at: indexToDelete)
            }
        }
    }
    
    
    

    Note this is a demo code, because I don’t know what’s your movement property is doing, or any other details which you haven’t shared. I guess you can update your code according to this demo.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search