Есть ли способ выполнить пакетное обновление массивов Swift? - PullRequest
0 голосов
/ 06 мая 2018

У меня есть массив из 1000+ предметов. Первоначально элементы массива имеют состояние initial.

В какой-то момент я хочу изменить состояние некоторых предметов на updated.

Если я меняю элементы массива один за другим, например, перебираю массив и обновляю их значения, если он удовлетворяет условию, при каждом обновлении я получаю обратный вызов для массива didSet.

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

Возможно ли это в Свифте?

Ответы [ 2 ]

0 голосов
/ 07 мая 2018

Другой способ пакетного обновления массива - передать его как переменную inout функции, которая его обновляет. Из-за семантики copy in - copy out inout массив будет обновляться только один раз:

class Foo {
    var arr: [Int] = [1,2,3,4,5] {
        didSet {
            print("SET")
        }
    }

    func batchUpdate(_ arr: inout [Int]) {
        for idx in arr.indices {
            arr[idx] *= 2
        }
    }

    func test() {
        batchUpdate(&arr)
        print(arr)
    }
}

Foo().test()
SET
[2, 4, 6, 8, 10]
0 голосов
/ 06 мая 2018

Самый простой способ сделать это - сделать копию, изменить ее так, как вам нравится, и затем вернуть ее обратно. Например:

var xs = [1,2,3,4] {
    didSet {
        print("SET")
    }
}

var ys = xs
ys[0] = 0
ys[2] = 100

xs = ys

(печатает "SET" только один раз.)

Прежде чем спросить: 1000 предметов - это не большой массив. Такое копирование нечасто, как правило, не является проблемой, если только сами хранимые элементы не очень большие. Но что, если копирование действительно окажется проблемой? Тогда вы можете пойти по небезопасному маршруту:

xs.withUnsafeMutableBufferPointer { (ptr) in
    ptr[0] = 1000
    ptr[1] = 2000
}

Я бы как-то обесценил map, чтобы решить это, но, пытаясь ответить Султану о том, почему, я как бы отговорил себя от этого. Вы можете определенно использовать map, особенно учитывая тот тип использования, о котором вы упоминали.

let updatedIndexes = [0, 2]
xs = xs.enumerated()
    .map { (n, value) in
        return updatedIndexes.contains(n) ? State.updated : value
}
...