Colecciones inmutables / mutables en Swift

88

Me refería a la guía de programación Swift de Apple para comprender la creación de objetos mutables / inmutables (matriz, diccionario, conjuntos, datos) en lenguaje Swift. Pero no pude entender cómo crear colecciones inmutables en Swift.

Me gustaría ver los equivalentes en Swift para lo siguiente en Objective-C

Matriz inmutable

NSArray *imArray = [[NSArray alloc]initWithObjects:@"First",@"Second",@"Third",nil];

Matriz mutable

NSMutableArray *mArray = [[NSMutableArray alloc]initWithObjects:@"First",@"Second",@"Third",nil];
[mArray addObject:@"Fourth"];

Diccionario inmutable

NSDictionary *imDictionary = [[NSDictionary alloc] initWithObjectsAndKeys:@"Value1", @"Key1", @"Value2", @"Key2", nil];

Diccionario mutable

NSMutableDictionary *mDictionary = [[NSMutableDictionary alloc]initWithObjectsAndKeys:@"Value1", @"Key1", @"Value2", @"Key2", nil];
[mDictionary setObject:@"Value3" forKey:@"Key3"];
Pranav Jaiswal
fuente

Respuestas:

115

Matrices

Crea una matriz inmutable

Primera forma:

let array = NSArray(array: ["First","Second","Third"])

Segunda forma:

let array = ["First","Second","Third"]

Crear matriz mutable

var array = ["First","Second","Third"]

Agregar objeto a la matriz

array.append("Forth")


Diccionarios

Crear diccionario inmutable

let dictionary = ["Item 1": "description", "Item 2": "description"]

Crear diccionario mutable

var dictionary = ["Item 1": "description", "Item 2": "description"]

Agregar nuevo par al diccionario

dictionary["Item 3"] = "description"

Más información sobre Apple Developer

nicael
fuente
12
La matriz de "longitud fija" sería más precisa. No es inmutable.
Sulthan
1
inmutable Dictionaryes verdaderamente inmutable (opuesto a Array)
Bryan Chen
@BryanChen Oh .. ¡Gracias!
nicael
@BryanChen Sí, me olvidé de eliminar var.
nicael
2
Sip. Más información sobre la inmutabilidad de las matrices en esta pregunta y sus respuestas .
Matt Gibson
31

Swift no tiene ningún reemplazo para NSArraylas otras clases de colección en Objective-C.

Hay clases de matriz y diccionario, pero debe tenerse en cuenta que se trata de tipos de "valor", en comparación con NSArray y NSDictionary, que son tipos de "objeto".

La diferencia es sutil pero puede ser muy importante para evitar errores de casos extremos.

Rápidamente, crea una matriz "inmutable" con:

let hello = ["a", "b", "c"]

Y una matriz "mutable" con:

var hello = ["a", "b", "c"]

Las matrices mutables se pueden modificar como NSMutableArray:

var myArray = ["a", "b", "c"]

myArray.append("d") // ["a", "b", "c", "d"]

Sin embargo, no puede pasar una matriz mutable a una función:

var myArray = ["a", "b", "c"]

func addToArray(myArray: [String]) {
  myArray.append("d") // compile error
}

Pero el código anterior funciona con NSMutableArray:

var myArray = ["a", "b", "c"] as NSMutableArray

func addToArray(myArray: NSMutableArray) {
  myArray.addObject("d")
}

addToArray(myArray)

myArray // ["a", "b", "c", "d"]

Puede lograr NSMutableArrayel comportamiento de usando un inoutparámetro de método:

var myArray = ["a", "b", "c"]

func addToArray(inout myArray: [String]) {
  myArray.append("d")
}

addToArray(&myArray)

myArray // ["a", "b", "c", "d"]

Reescribió esta respuesta 2015-08-10 para reflejar el comportamiento actual de Swift.

Abhi Beckert
fuente
1
Obviamente, esto ha cambiado ahora. Una matriz constante ahora es verdaderamente inmutable, y una matriz variable ahora es verdaderamente mutable. Se pasan como valores , por lo que se copiarán cuando se asignen a otra variable o se pasen entre funciones. Sin embargo, esto no tiene nada que ver con la mutabilidad o la inmutabilidad.
Balthazar
Además, como mencioné en mi respuesta, pasar como valores es relevante para la mutabilidad / inmutabilidad, ya que la única vez que le importa eso es cuando pasa una matriz a otro código (que puede modificarla).
Abhi Beckert
Pero si accede a la matriz como una propiedad, aún puede modificarla desde otro objeto. Uno de los beneficios de una matriz inmutable es que puede pasarla de forma segura a otro objeto, sin preocuparse de si el otro objeto puede modificar el original. Esta preocupación ya no existe cuando los objetos se pasan como valores. Entonces, diferentes semánticas requieren diferentes prácticas de codificación. EDITAR: Ahora veo que ha modificado la redacción de la publicación, así que estamos de acuerdo. Estoy de acuerdo en que las diferencias son importantes para conocer Wrt. el uso de colecciones mutables.
Balthazar
6

Solo hay uno Arrayy un Dictionarytipo en Swift. La mutabilidad depende de cómo la construyas:

var mutableArray = [1,2,3]
let immutableArray = [1,2,3]

es decir, si crea una asignación a una variable, es mutable, mientras que si crea una asignación a una constante, no lo es.

ADVERTENCIA: ¡Las matrices inmutables no son completamente inmutables! Aún puede cambiar su contenido, ¡pero no su longitud total!

ColinE
fuente
1
Para su información: el comportamiento de la matriz está cambiando en una próxima versión beta; Creo que todos apilados en uno de eso
russbishop
@xenadu Fuente? ¿ETA en esa beta?
Archivo analógico
Lo siento, no hay fuente. Provino de una discusión con uno de los miembros del equipo del compilador. También dijo que Beta 2 era básicamente solo un par de correcciones de errores ya verificadas y no tiene nada relacionado con los comentarios posteriores a la WWDC.
russbishop
5

Simplemente declare su (cualquier) objeto o variable con

'let' key word -> for "constan/Immutable" array, dictionary, variable, object..etc.

y

'var' key word -> for "Mutable" array, dictionary, variable, object..etc. 

Para obtener información más detallada

“Use let para hacer una constante y var para hacer una variable. No es necesario conocer el valor de una constante en tiempo de compilación, pero debe asignarle un valor exactamente una vez. Esto significa que puede usar constantes para nombrar un valor que determina una vez pero que usa en muchos lugares ".

var myVariable = 42
myVariable = 50
let myConstant = 42

Lea "El lenguaje de programación Swift".

iPatel
fuente
Bueno, en el caso de una matriz, esto no funciona como se esperaba. stackoverflow.com/a/24319712/623710
macshome
3

Si desea trabajar con Array(Swift) como con NSArray, puede usar una función de puente simple. Ejemplo:

var arr1 : Array = []

arr1.bridgeToObjectiveC().count

Funciona igual para let.

Moti F.
fuente
0

De los propios documentos de Apple:

Mutabilidad de colecciones

Si crea una matriz, un conjunto o un diccionario y lo asigna a una variable, la colección que se crea será mutable. Esto significa que puede cambiar (o mutar) la colección después de su creación agregando, quitando o cambiando elementos en la colección. Por el contrario, si asigna una matriz, un conjunto o un diccionario a una constante, esa colección es inmutable y su tamaño y contenido no se pueden cambiar.

https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html#//apple_ref/doc/uid/TP40014097-CH8-ID105

Otros usos de las colecciones inmutables / mutables dependen de por qué desea que sean mutables / inmutables. Las colecciones son tipos de valor en Swift, lo que significa que su contenido se copia cuando se asigna a otro valor o se pasa a otra función / método. Por lo tanto, no necesita preocuparse por si una función del método de recepción podría cambiar la matriz original. Por lo tanto, no necesita asegurarse de devolver una colección inmutable si su clase tiene una colección mutable, por ejemplo.

Baltasar
fuente
0

[No modificable e inmutable]

La matriz de Swift se puede silenciar

[let vs var, valor vs tipo de referencia]

Colección inmutable [Acerca de] - es una estructura de colección que no se puede cambiar. Significa que no puede agregar, eliminar, modificar después de la creación.

let + struct(como Array, Set, Dictionary) es más conveniente ser inmutable

Hay algunas clases (por ejemplo NSArray) que no proporcionan una interfaz para cambiar el estado interno

pero

class A {
    var value = "a"
}

func testMutability() {
    //given
    let a = A()
    
    let immutableArr1 = NSArray(array: [a])
    let immutableArr2 = [a]
    
    //when
    a.value = "aa"
    
    //then
    XCTAssertEqual("aa", (immutableArr1[0] as! A).value)
    XCTAssertEqual("aa", immutableArr2[0].value)
}   

Preferiría ser una unmodifiablematriz

yoAlex5
fuente