Coleções imutáveis ​​/ mutáveis ​​em Swift

88

Eu estava me referindo ao guia de programação Swift da Apple para compreender a criação de objetos mutáveis ​​/ imutáveis ​​(Array, Dicionário, Conjuntos, Dados) na linguagem Swift. Mas eu não conseguia entender como criar coleções imutáveis ​​em Swift.

Eu gostaria de ver os equivalentes em Swift para o seguinte em Objective-C

Matriz Imutável

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

Matriz Mutável

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

Dicionário imutável

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

Dicionário Mutável

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

Respostas:

115

Arrays

Crie uma matriz imutável

Primeira maneira:

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

Segunda forma:

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

Criar matriz mutável

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

Anexar objeto ao array

array.append("Forth")


Dicionários

Crie um dicionário imutável

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

Crie um dicionário mutável

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

Anexar novo par ao dicionário

dictionary["Item 3"] = "description"

Mais informações sobre Apple Developer

nicael
fonte
12
A matriz de "comprimento fixo" seria mais precisa. Não é imutável.
Sulthan
1
imutável Dictionaryé verdadeiramente imutável (oposto a Array)
Bryan Chen
@BryanChen Oh .. Obrigado!
nicael
@BryanChen Sim, esqueci de remover var.
nicael
2
Sim. Mais informações sobre a imutabilidade de arrays nesta pergunta e suas respostas .
Matt Gibson
31

O Swift não tem nenhuma queda na substituição NSArrayou nas outras classes de coleção em Objective-C.

Existem classes de matriz e dicionário, mas deve-se observar que esses são tipos de "valor", em comparação com NSArray e NSDictionary, que são tipos de "objeto".

A diferença é sutil, mas pode ser muito importante para evitar bugs de casos extremos.

Em swift, você cria uma matriz "imutável" com:

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

E uma matriz "mutável" com:

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

Matrizes mutáveis ​​podem ser modificadas como NSMutableArray:

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

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

No entanto, você não pode passar uma matriz mutável para uma função:

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

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

Mas o código acima funciona com um NSMutableArray:

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

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

addToArray(myArray)

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

Você pode obter NSMutableArrayo comportamento de usando um 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"]

Reescreveu esta resposta 10/08/2015 para refletir o comportamento atual do Swift.

Abhi Beckert
fonte
1
Isso obviamente foi mudado agora. Um array constante agora é verdadeiramente imutável e um array variável agora é verdadeiramente mutável. Eles são passados ​​como valores , portanto, serão copiados quando atribuídos a outra variável ou passados ​​entre funções. Isso, entretanto, nada tem a ver com mutabilidade ou imutabilidade.
Balthazar
Além disso, como mencionei na minha resposta, ser passado como valores é relevante para a mutabilidade / imutabilidade, pois a única vez que você se preocupa com isso é ao passar um array para outro código (que pode modificá-lo).
Abhi Beckert
Mas se você acessar a matriz como uma propriedade, ainda poderá modificá-la a partir de outro objeto. Um dos benefícios de um array imutável é que você pode passá-lo com segurança para outro objeto, sem se preocupar se o outro objeto pode modificar o original. Essa preocupação não existe mais quando os objetos são passados ​​como valores. Portanto, semânticas diferentes requerem práticas de codificação diferentes. EDIT: Agora vejo que você reformulou a postagem, então concordamos. Eu concordo que as diferenças são importantes para estar ciente de wrt. o uso de coleções mutáveis.
Balthazar de
6

Existe apenas um Arraye um Dictionarytipo no Swift. A mutabilidade depende de como você a constrói:

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

ou seja, se você criar uma atribuição para uma variável, ela será mutável, mas se você criar uma atribuição para uma constante, ela não será.

AVISO: Matrizes imutáveis ​​não são totalmente imutáveis! Você ainda pode alterar o conteúdo, mas não o comprimento total!

ColinE
fonte
1
FYI: o comportamento do array está mudando em um beta que está por vir; Acho que todo mundo empilhou sobre isso
russbishop
Fonte @xenadu? ETA nesse beta?
Arquivo analógico de
Desculpe, nenhuma fonte. Ele veio de uma discussão com um dos membros da equipe do compilador. Ele também disse que o Beta 2 era basicamente apenas um par de correções de bugs já checados e não tinha nada relacionado ao feedback pós-WWDC.
russbishop
5

Basta declarar seu (qualquer) objeto ou variável com

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

e

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

Para informações mais detalhadas

“Use let para fazer uma constante e var para fazer uma variável. O valor de uma constante não precisa ser conhecido no momento da compilação, mas você deve atribuir um valor a ela exatamente uma vez. Isso significa que você pode usar constantes para nomear um valor que você determina uma vez, mas usa em muitos lugares. "

var myVariable = 42
myVariable = 50
let myConstant = 42

Leia “A linguagem de programação rápida”.

iPatel
fonte
Bem, no caso de um Array, isso não funciona conforme o esperado. stackoverflow.com/a/24319712/623710
macshome
3

Se você deseja trabalhar com Array(Swift) como com NSArray, pode usar uma função de ponte simples. Exemplo:

var arr1 : Array = []

arr1.bridgeToObjectiveC().count

Funciona da mesma forma para let.

Moti F.
fonte
0

Dos próprios documentos da Apple:

Mutabilidade de coleções

Se você criar uma matriz, um conjunto ou um dicionário e atribuí-lo a uma variável, a coleção criada será mutável. Isso significa que você pode alterar (ou modificar) a coleção após sua criação, adicionando, removendo ou alterando itens na coleção. Por outro lado, se você atribuir um array, um conjunto ou um dicionário a uma constante, essa coleção é imutável e seu tamanho e conteúdo não podem ser alterados.

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

Outros usos de coleções imutáveis ​​/ mutáveis ​​dependem de por que você deseja que elas sejam mutáveis ​​/ imutáveis. Coleções são tipos de valor em Swift, o que significa que seu conteúdo é copiado quando atribuído a outro valor ou passado para outra função / método. Portanto, você não precisa se preocupar se uma função de método de recebimento pode alterar o array original. Portanto, você não precisa garantir o retorno de uma coleção imutável se sua classe está mantendo uma coleção mutável, por exemplo.

Balthazar
fonte
0

[Não modificável e imutável]

O array do Swift pode ser silenciado

[let vs var, Value vs Reference Type]

Coleção imutável [Sobre] - é uma estrutura de coleção que não pode ser alterada. Isso significa que você não pode adicionar, remover, modificar após a criação

let + struct(como Array, Set, Dictionary) é mais adequado para ser imutável

Existem algumas classes (por exemplo NSArray) que não fornecem uma interface para alterar o estado interno

mas

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)
}   

Ele prefere ser unmodifiablearray

yoAlex5
fonte