arrays - referencia - paso arreglo de funciones
Swift: ¿pasar matriz por referencia? (8)
Algo como
var a : Int[] = []
func test(inout b : Int[]) {
b += [1,2,3,4,5]
}
test(&a)
println(a)
???
Quiero pasar mi Swift Array
chatsViewController.chats
a chatsViewController.chats
por referencia (para que cuando agregue un chat a chatsViewController.chats
, chatsViewController.chats
siga chatsViewController.chats
). Es decir, no quiero que Swift separe las dos matrices cuando cambie la longitud de account.chats
.
Defina usted mismo un BoxedArray<T>
que implemente la interfaz Array
pero delegue todas las funciones en una propiedad almacenada. Como tal
class BoxedArray<T> : MutableCollection, Reflectable, ... {
var array : Array<T>
// ...
subscript (index: Int) -> T {
get { return array[index] }
set(newValue) { array[index] = newValue }
}
}
Usa el BoxedArray
cualquier lugar donde uses una Array
. La asignación de un BoxedArray
será por referencia, es una clase, y por lo tanto los cambios a la propiedad almacenada, a través de la interfaz Array
, serán visibles para todas las referencias.
Las estructuras en Swift se pasan por valor, pero puedes usar el modificador inout
para modificar tu matriz (ver respuestas a continuación). Las clases se pasan por referencia. Array
y Dictionary
in Swift se implementan como estructuras.
Otra opción es hacer que el consumidor de la matriz pregunte al propietario si es necesario. Por ejemplo, algo como:
class Account {
var chats : [String]!
var chatsViewController : ChatsViewController!
func InitViewController() {
chatsViewController.getChats = { return self.chats }
}
}
class ChatsViewController {
var getChats: (() -> ([String]))!
func doSomethingWithChats() {
let chats = getChats()
// use it as needed
}
}
A continuación, puede modificar la matriz tanto como desee dentro de la clase Cuenta. Tenga en cuenta que esto no lo ayudará si también desea modificar la matriz de la clase de controlador de vista.
Para el operador del parámetro de función usamos:
let (es el operador predeterminado, por lo que podemos omitir let ) para hacer un parámetro constante (significa que no podemos modificar incluso la copia local);
var para hacerlo variable (podemos modificarlo localmente, pero no afectará a la variable externa que se ha pasado a la función); y
inout para convertirlo en un parámetro in-out. In-out significa, de hecho, pasar variable por referencia, no por valor. Y requiere no solo aceptar el valor por referencia, sino también pasarlo por referencia, así que foo(&myVar)
con & - foo(&myVar)
lugar de solo foo(myVar)
Entonces hazlo así:
var arr = [1, 2, 3]
func addItem(inout localArr: [Int]) {
localArr.append(4)
}
addItem(&arr)
println(arr) // it will print [1, 2, 3, 4]
Para ser exactos, no es solo una referencia, sino un alias real para la variable externa, por lo que puede hacer ese truco con cualquier tipo de variable, por ejemplo, con entero (puede asignarle un nuevo valor), aunque puede que no sea un buenas prácticas y puede ser confuso modificar los tipos de datos primitivos como este.
Para las versiones 3-4 de Swift (XCode 8-9), use
var arr = [1, 2, 3]
func addItem(_ localArr: inout [Int]) {
localArr.append(4)
}
addItem(&arr)
print(arr)
Swift 3 y Xcode 8:
var myArray = [1, 2, 3]
for (index, value) in myArray.enumerated() {
// if you don''t need the value you could do: for (index, _) in myArray.enumerated()
myArray[index].append(4)
}
Usar inout
es una solución, pero no me parece muy fácil porque las matrices son tipos de valores. Estilísticamente, personalmente prefiero devolver una copia mutada:
func doSomething(to arr: [Int]) -> [Int] {
var arr = arr
arr.append(3) // or likely some more complex operation
return arr
}
var ids = [1, 2]
ids = doSomething(to: ids)
print(ids) // [1,2,3]