'Swift - Get array item with an IndexSet

I have my Contact object:

struct Contact: Codable, Identifiable {
    var id: Int = 0
    var name: String
    var lastName: String
    var phoneNumber: String
}

And in my view I have a list of contacts that will be fetched from a server.

List {
    ForEach(viewModel.contacts) { contact in
        ContactView(contact: contact)
    }
    .onDelete(perform: self.viewModel.delete)
}

When I delete a contact I call my viewModel method delete which only removes the item from the array. But since I will make a server request to delete a contact, I would like to get info about the item I'm deleting, like the Id.

class ContactsViewModel: ObservableObject {
    @Published contacts = [
        Contact(id: 1, name: "Name 1", lastName: "Last Name 1", phoneNumber: "613456789"),
        Contact(id: 2, name: "Name 2", lastName: "Last Name 2", phoneNumber: "623456789"),
        Contact(id: 3, name: "Name 3", lastName: "Last Name 3", phoneNumber: "633456789"),
        Contact(id: 4, name: "Name 4", lastName: "Last Name 4", phoneNumber: "643456789")
    ]
    func delete(at offsets: IndexSet) {
        self.contacts.remove(atOffsets: offsets)
    }
}

I wonder if I can do something like this:

func delete(at offsets: IndexSet) {
    // Get the contact from array using the IndexSet
    let itemToDelete = self.contacts.get(at: offsets)

    deleteRequest(itemToDelete.id){ success in 
        if success {
            self.contacts.remove(atOffsets: offsets)
        }
    }
}


Solution 1:[1]

Taking into account that mentioned deleteRequest semantically is asynchronous and there might be, in general, several contacts deleted in one user action, I would do it like below

func delete(at offsets: IndexSet) {

    // preserve all ids to be deleted to avoid indices confusing
    let idsToDelete = offsets.map { self.contacts[$0].id }

    // schedule remote delete for selected ids
    _ = idsToDelete.compactMap { [weak self] id in
        self?.deleteRequest(id){ success in
            if success {
                DispatchQueue.main.async {
                    // update on main queue
                    self?.contacts.removeAll { $0.id == id }
                }
            }
        }
    }
}

Note: also some feedback in UI would be needed marking progressed contacts and disabling user from other manipulations with them till end of corresponding deleteRequest

backup

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1