Неизменяемые / изменчивые коллекции в Swift

Я имел в виду руководство по программированию Apple Swift для понимания создания изменяемых / неизменяемых объектов (Array, Dictionary, Sets, Data) на языке Swift. Но я не мог понять, как создавать неизменные коллекции в Swift.

Я хотел бы видеть эквиваленты в Swift для следующего в Objective-C

Неизменный массив

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

Изменяемый массив

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

Неизменный словарь

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

Изменчивый словарь

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

7 ответов

Решение

Массивы

Создать неизменный массив

Первый способ:

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

Второй способ:

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

Создать изменяемый массив

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

Добавить объект в массив

array.append("Forth")


Словари

Создать неизменный словарь

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

Создать изменяемый словарь

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

Добавить новую пару в словарь

dictionary["Item 3"] = "description"

Больше информации о Apple Developer

У Swift нет ни капли в замене NSArray или другие классы коллекции в Objective-C.

Существуют классы массивов и словарей, но следует отметить, что это типы "значения" по сравнению с NSArray и NSDictionary, которые являются типами "объект".

Разница невелика, но может быть очень важной, чтобы избежать ошибок в крайнем случае.

В swift вы создаете "неизменяемый" массив с:

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

И "изменяемый" массив с:

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

Изменяемые массивы могут быть изменены так же, как NSMutableArray:

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

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

Однако вы не можете передать изменяемый массив в функцию:

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

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

Но приведенный выше код работает с NSMutableArray:

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

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

addToArray(myArray)

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

Вы можете достичь NSMutableArrayповедение с помощью inout параметр метода:

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

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

addToArray(&myArray)

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

Переписал этот ответ 2015-08-10, чтобы отразить текущее поведение Swift.

Здесь только один Array и один Dictionary введите Свифт. Изменчивость зависит от того, как вы ее построите:

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

т.е. если вы создаете присвоение переменной, оно является изменчивым, тогда как если вы создаете присвоение константе, это не так.

ВНИМАНИЕ: неизменяемые массивы не являются полностью неизменяемыми! Вы все еще можете изменить их содержимое, но не их общую длину!

Просто объявите свой (любой) объект или переменную с помощью

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

а также

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

Для более глубокой информации

"Используйте let для создания константы и var для создания переменной. Значение константы не нужно знать во время компиляции, но вы должны присвоить ей значение ровно один раз. Это означает, что вы можете использовать константы для именования значения, которое вы определяете один раз, но используете во многих местах."

var myVariable = 42
myVariable = 50
let myConstant = 42

Прочитайте "Язык программирования Swift".

Если вы хотите работать с Array (Свифт) как с NSArray, вы можете использовать простую функцию моста. Пример:

var arr1 : Array = []

arr1.bridgeToObjectiveC().count

Это работает так же для let,

Из собственных документов Apple:

Изменчивость коллекций

Если вы создаете массив, набор или словарь и присваиваете его переменной, созданная коллекция будет изменчивой. Это означает, что вы можете изменить (или изменить) коллекцию после ее создания, добавляя, удаляя или изменяя элементы в коллекции. И наоборот, если вы присваиваете константу массив, набор или словарь, эта коллекция является неизменной, и ее размер и содержимое не могут быть изменены.

https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html

Другое использование неизменяемых / изменяемых коллекций зависит от того, почему вы хотите, чтобы они были изменяемыми / неизменяемыми. Коллекции являются типами значений в Swift, что означает, что их содержимое копируется, когда они присваиваются другому значению или передаются другой функции / методу. Следовательно, вам не нужно беспокоиться о том, может ли функция-получатель изменить исходный массив. Поэтому вам не нужно возвращать неизменяемую коллекцию, например, если ваш класс содержит изменяемую коллекцию.

[Неизменяемый и неизменный]

Массив Swift можно отключить

[let vs var, значение vs тип ссылки]

Неизменяемая коллекция [О программе] - это коллекция, структура которой не может быть изменена. Это означает, что вы не можете добавлять, удалять, изменять после создания

let + struct(подобно Array, Set, Dictionary) более подходит, чтобы быть неизменным

Есть несколько классов (например, NSArray), который не предоставляет интерфейс для изменения внутреннего состояния

но

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

Было бы лучше unmodifiable массив

Там нет встроенного актерского состава для этого. Но вместо этого вы можете использовать инициализатор NSMutableDictionary, который принимает словарь:

var foundationDictionary = NSMutableDictionary(dictionary: dictionary)
Другие вопросы по тегам