Объекты массива Swift swap

Я не могу поменять массив строк на переупорядочивание ячеек

var scatola : [String] = []

override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
        swap(&scatola[fromIndexPath.row], &scatola[toIndexPath.row])
    }

этот код бросает: inout writeback к вычисленному свойству "scatola" встречается в нескольких аргументах для вызова, внося неверный псевдоним

Каков правильный способ сделать это?

Ответ 1

Обновление:. По сравнению с Swift 3.2/4 (Xcode 9) вы должны использовать метод swapAt() для коллекция

 scatola.swapAt(fromIndexPath.row, toIndexPath.row)

потому что передавая массив как два разных inout аргументы одной и той же функции больше не являются законными, сравните SE-0173 Добавить MutableCollection.swapAt(_:_:)).


Обновление: Я снова проверил код с Xcode 6.4, и проблема больше не происходит. Он компилируется и работает как ожидалось.


(Старый ответ:) Я предполагаю, что scatola является сохраненным свойством в контроллере представления:

var scatola : [Int] = []

Ваша проблема, похоже, связана с проблемой, обсуждаемой в https://devforums.apple.com/thread/240425. Он уже может быть воспроизведен с помощью:

class MyClass {
    var array = [1, 2, 3]

    func foo() {
        swap(&array[0], &array[1])
    }
}

Выход компилятора:

error: inout writeback to computed property 'array' occurs in multiple arguments to call, introducing invalid aliasing
        swap(&array[0], &array[1])
                         ^~~~~~~~
note: concurrent writeback occurred here
        swap(&array[0], &array[1])
              ^~~~~~~~

Я еще не понял содержание обсуждения полностью (слишком поздно здесь:), но есть один предложенный "обходной путь", а именно, чтобы отметить свойство как окончательное (чтобы вы не могли его переопределить в подклассе):

final var scatola : [Int] = []

Другим обходным решением, которое я нашел, является получение указателя на хранилище базового массива:

scatola.withUnsafeMutableBufferPointer { (inout ptr:UnsafeMutableBufferPointer<Int>) -> Void in
    swap(&ptr[fromIndexPath.row], &ptr[toIndexPath.row])
}

Конечно, безупречное решение было бы просто

let tmp = scatola[fromIndexPath.row]
scatola[fromIndexPath.row] = scatola[toIndexPath.row]
scatola[toIndexPath.row] = tmp

Ответ 2

В качестве альтернативы,

let f = fromIndexPath.row, t = toIndexPath.row
(scatola[f], scatola[t]) = (scatola[t], scatola[f])

Ответ 3

Начиная Xcode 9, вы можете написать:

@objc override func tableView(_ tableView: UITableView, 
                moveRowAt sourceIndexPath: IndexPath, 
                  to destinationIndexPath: IndexPath) {
    scatola.swapAt(sourceIndexPath.row, destinationIndexPath.row)
}