简体   繁体   中英

Swift swap array objects

I'm unable to swap an array of strings on cell reorder

var scatola : [String] = []

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

this code throws: inout writeback to computed property 'scatola' occurs in multiple arguments to call, introducing invalid aliasing

what is the right way to do it?

Update: As of Swift 3.2/4 (Xcode 9) you have to use the swapAt() method on the collection

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

because passing the array as two different inout arguments to the same function is no longer legal, compare SE-0173 Add MutableCollection.swapAt(_:_:) ).


Update: I tested the code again with Xcode 6.4 , and the problem does not occur anymore. It compiles and runs as expected.


(Old answer:) I assume that scatola is a stored property in the view controller:

var scatola : [Int] = []

Your problem seems be related to the problem discussed in https://devforums.apple.com/thread/240425 . It can already be reproduced with:

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

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

Compiler output:

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])
              ^~~~~~~~

I haven't yet grasped the contents of the discussion completely (too late here :), but there is one proposed "workaround", namely to mark the property as final (so that you cannot override it in a subclass):

final var scatola : [Int] = []

Another workaround that I found is to get a pointer on the underlying array storage:

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

Of course, the fool-proof solution would simply be

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

Alternatively,

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

Starting Xcode 9, you can write:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM