Найти элемент и изменить значение в настраиваемом массиве объектов - Swift

У меня этот класс

class InboxInterests {

    var title = ""
    var eventID = 0
    var count = ""
    var added = 0

    init(title : String, eventID : NSInteger, count: String, added : NSInteger) {
        self.title = title
        self.eventID = eventID
        self.count = count
        self.added = added

    }
}

И я использую его как это

var array: [InboxInterests] = [InboxInterests]()

Добавить элемент

let post = InboxInterests(title: "test",eventID : 1, count: "test", added: 0)
self.array.append(post)

Я хочу найти индекс клавишей eventID и изменить значение added в том же индексе

Как это возможно?

Ответ 1

Используйте фильтр и сначала найдите значение:

array.filter({$0.eventID == id}).first?.added = value

В этом вы:

  1. фильтровать массив до элементов, соответствующих идентификатору события
  2. выберите первый результат, если есть
  3. затем установите значение

РЕДАКТИРОВАТЬ: В Swift 3 вы можете сохранить себе пару символов

array.first({$0.eventID == id})?.added = value

РЕДАКТИРОВАТЬ: Swift 4.2:

array.first(where: { $0.eventID == id })?.added = value
array.filter {$0.eventID == id}.first?.added = value

Ответ 2

Для меня вышеуказанный ответ не сработал. Итак, сначала я нашел индекс объекта, который я хочу заменить, а затем с помощью индекса заменил его новым значением.

if let row = self.upcoming.index(where: {$0.eventID == id}) {
       array[row] = newValue
}

В Swift 5.0:

if let row = self.upcoming.firstIndex(where: {$0.eventID == id}) {
       array[row] = newValue
}

Ответ 3

В этом случае оператор фильтра не самый лучший, он работает для некоторых из вас, потому что классы передаются по ссылке.

Объяснение: (Вы можете скопировать следующий код на игровой площадке, если вы хотите его проверить).

class Book {
    let id: Int
    var title = "default"

    init (id: Int) {
        self.id = id
    }
}
var arrayBook = [Book]()
arrayBook.append(Book(id: 0))
arrayBook.append(Book(id:1))
arrayBook.forEach { book in
    print(book.title)
}

arrayBook.filter{ $0.id == 1 }.first?.title = "modified"

arrayBook.forEach { book in
    print(book.title)
}

Массивы копируются по значению not reference, поэтому, когда вы используете фильтр, вы создаете новый массив (отличный от исходного), но когда вы изменяете новый, исходный изменяется также, потому что оба указывают на тот же класс (classed передаются по ссылке), поэтому после фильтра ваш массив будет изменен, а новый будет освобожден. Таким образом, в этом случае он будет печатать " по умолчанию", "по умолчанию" , а затем "по умолчанию," изменено ".

Что произойдет, если вы измените class на struct, значение будет передано значением not reference, так что у вас будет 2 массива в памяти с разными значениями, поэтому, если вы перейдете через arrayBooks снова, он будет распечатываться раньше фильтр "по умолчанию" , "по умолчанию" , а затем "по умолчанию" , "по умолчанию" . Потому что, когда вы используете фильтр, который вы создаете и изменяете новый массив, который будет освобожден, если вы его не сохраните).

Решение использует карту, создавая новый массив со всеми значениями, но с измененными элементами или полями, которые мы хотим, а затем заменим наш массив новым. Это приведет к печати "по умолчанию" , "по умолчанию" до карты, а затем "по умолчанию" , "изменено"

Это будет работать с структурами, классами и всем, что вы хотите:).

struct Book {
    let id: Int
    var title = "default"

    init (id: Int) {
        self.id = id
    }
}
var arrayBook = [Book]()
arrayBook.append(Book(id: 0))
arrayBook.append(Book(id:1))
arrayBook.forEach { book in
    print(book.title)
}

arrayBook = arrayBook.map{
    var mutableBook = $0
    if $0.id == 1 {
        mutableBook.title = "modified"
    }
    return mutableBook
}

arrayBook.forEach { book in
    print(book.title)
}