Мое понимание:
Массивы в Swift являются типами значений. Массивы и другие коллекции в Swift имеют механизм CoW (Copy on Write), поэтому, когда массив передается в качестве аргумента функции или просто назначается другой переменной, Swift фактически не создает другую копию массива, а просто передает ссылку на тот же массив. . При попытке записи/изменения массива Swift создаст новую копию массива (при условии, что исходная ссылка на массив все еще сильно удерживается), и операция записи будет выполняться для новой копии массива.
Предыстория:
В этой проблеме я пытаюсь сохранить экземпляры классов (ссылочные типы в массиве)
class TestClass {
var name: String = "abcd"
init(name: String) {
self.name = name
}
}
Я создаю локальную переменную a (массив) из TestClass
и передаю ее в качестве аргумента someFunc
override func viewDidLoad() {
super.viewDidLoad()
var a = [TestClass(name: "abcd"), TestClass(name: "efgh"), TestClass(name: "ijkl")]
debugPrint(UnsafePointer(&a))
self.someFunc(array: a)
}
В someFunc
я присваиваю аргумент другой переменной anotherArray
и выполняю append
операцию над anotherArray
. Поскольку ожидается, что CoW массива срабатывает и создает новую копию массива, поэтому адреса памяти array
и anotherArray
различны.
func someFunc(array: [TestClass]) {
var anotherArray = array
anotherArray.append(TestClass(name: "mnop"))
debugPrint(UnsafePointer(&array))
debugPrint(UnsafePointer(&anotherArray))
}
Как и ожидалось, когда тип значения копируется, все внутренние ссылочные типы также будут воссозданы/скопированы, чтобы доказать, что
func someFunc(array: [TestClass]) {
var anotherArray = array
anotherArray.append(TestClass(name: "mnop"))
for var value in array {
debugPrint(UnsafePointer(&value))
}
for var value in anotherArray {
debugPrint(UnsafePointer(&value))
}
}
Ясно, что адреса памяти массивов разные (array !=== anotherArray
), а также адреса памяти всех элементов внутри array
и anotherArray
тоже разные (array[i] !=== anotherArray[i]
)
Проблема:
func someFunc(array: [TestClass]) {
var anotherArray = array
anotherArray.append(TestClass(name: "mnop"))
anotherArray[0].name = "Sandeep"
debugPrint(array[0].name)
}
При четком понимании того, что массив и другой массив являются двумя разными копиями, а также ссылочные типы внутри каждого массива совершенно разные, можно было бы ожидать, что если я изменю значение anotherArray[0].name
на «Sandeep», array[0].name
все еще должно быть «abcd», но он возвращает «Sandeep "
Почему это? Я что-то упустил здесь? Это как-то связано со специальным средством доступа Array mutableAddressWithPinnedNativeOwner
?
Специальный метод доступа массива mutableAddressWithPinnedNativeOwner
Если я правильно понимаю, вместо того, чтобы просто извлекать значение по определенному индексу, копировать его, изменять и заменять исходное значение, как в случае Словарь, mutableAddressWithPinnedNativeOwner
просто получить доступ к физической памяти значения по адресу определенный индекс и изменяет его. Но это не должно иметь значения, когда изменяется весь массив :| Я запутался здесь
Полный рабочий код:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var a = [TestClass(name: "abcd"), TestClass(name: "efgh"), TestClass(name: "ijkl")]
debugPrint(UnsafePointer(&a))
self.someFunc(array: a)
// Do any additional setup after loading the view.
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
func someFunc(array: [TestClass]) {
var anotherArray = array
anotherArray.append(TestClass(name: "mnop"))
for var value in array {
debugPrint(UnsafePointer(&value))
}
for var value in anotherArray {
debugPrint(UnsafePointer(&value))
}
anotherArray[0].name = "Sandeep"
debugPrint(array[0].name)
}
}
0x00007ffee4efce38
и0x00007ffee4efce40
соответственно. - person Sandeep Bhandari   schedule 03.05.20200df8
и 4 на0e00
- person vadian   schedule 03.05.2020