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

88

Я имел в виду руководство Apple по программированию Swift для понимания создания изменяемых / неизменяемых объектов (массив, словарь, наборы, данные) на языке 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"];
Пранав Джайсвал
источник

Ответы:

115

Массивы

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

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

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

никель
источник
12
Массив «фиксированной длины» был бы более точным. Это не непреложно.
Sulthan
1
immutable Dictionaryдействительно неизменен (в отличие от Array)
Брайан Чен
@BryanChen Ой .. Спасибо!
nicael 07
@BryanChen Ага, забыл удалить var.
nicael 07
2
Ага. Подробнее о неизменности массивов в этом вопросе и ответах на него .
Мэтт Гибсон
31

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"]

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

Абхи Бекерт
источник
1
Очевидно, сейчас это изменилось. Постоянный массив теперь действительно неизменяем, а массив переменных теперь действительно изменчив. Они передаются как значения , поэтому они будут скопированы при присвоении другой переменной или передаче между функциями. Однако это не имеет ничего общего с изменчивостью или неизменяемостью.
Бальтазар
Также, как я уже упоминал в своем ответе, передача в качестве значений имеет отношение к изменчивости / неизменности, поскольку единственный раз, когда вам это нужно, - это передача массива в другой код (который может его изменить).
Абхи Бекерт,
Но если вы обращаетесь к массиву как к свойству, вы все равно можете изменить его из другого объекта. Одно из преимуществ неизменяемого массива заключается в том, что вы можете безопасно передать его другому объекту, не беспокоясь о том, может ли другой объект изменить оригинал. Эта проблема больше не существует, когда объекты передаются как значения. Итак, разная семантика требует разных практик кодирования. РЕДАКТИРОВАТЬ: теперь я вижу, что вы изменили формулировку сообщения, поэтому мы согласны. Я согласен, что важно знать о различиях в написании. использование изменяемых коллекций.
Бальтазар
6

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

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

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

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

Колин
источник
1
К вашему сведению: в предстоящей бета-версии поведение массива изменится; Я думаю, что все навалились на это
russbishop
@xenadu Источник? ETA на этой бета-версии?
Analog File
Извините, источника нет. Это произошло в результате обсуждения с одним из членов команды компилятора. Он также сказал, что Beta 2 - это всего лишь пара уже проверенных исправлений ошибок и не имеет ничего общего с отзывами после WWDC.
russbishop
5

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

'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

Прочтите «Быстрый язык программирования».

iPatel
источник
Что ж, в случае с массивом это работает не так, как ожидалось. stackoverflow.com/a/24319712/623710
macshome
3

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

var arr1 : Array = []

arr1.bridgeToObjectiveC().count

То же самое работает для let.

Моти Ф.
источник
0

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

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

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

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

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

Бальтазар
источник
0

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

Массив 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массив

yoAlex5
источник