Рассмотрите массив экземпляров классов: после присваивания его другой переменной изменение свойства элемента отражается в обоих массивах. Какой механизм Swift объясняет этот результат?
Массив имеет value semantics, но его элементы-классы имеют reference semantics. При присваивании массива Swift может отделить хранилища самих массивов, однако ссылки внутри них продолжают указывать на те же экземпляры классов. Поэтому изменение свойства объекта видно через обе переменные, пока не создан отдельный экземпляр.
Swift сочетает два подхода к семантике данных: структуры и перечисления обычно передаются как значения, а классы — как ссылки на общий объект. Такое разделение позволяет получать предсказуемое поведение небольших моделей значений и совместно использовать изменяемое состояние там, где это действительно требуется.
Коллекции Swift сохраняют value semantics поверх механизма Copy-on-Write. Это означает, что копирование коллекции логически создаёт независимое значение, но физическое копирование элементов откладывается до необходимости. Для ссылочных элементов независимость коллекций не означает независимость объектов.
После копирования массива разработчик может ошибочно ожидать, что изменение свойства элемента затронет только копию. На самом деле копируются ссылки, а не экземпляры классов, поэтому изменение общего объекта становится видимым через оба массива.
При этом структурная модификация массива, например добавление элемента, отделяет хранилища массивов. В результате один массив может получить другую длину, хотя уже существующие элементы-классы в обоих массивах всё ещё могут быть общими.
У массива есть собственная семантика значения: переменная хранит логически самостоятельное значение коллекции. Но элемент типа класса — это ссылка на объект в памяти. Копирование массива копирует расположение элементов, а для элемента-класса — саму ссылку.
До изменения свойства оба массива содержат ссылки на один объект User, поэтому имя изменяется для обоих наблюдателей. При добавлении элемента меняется структура только second; механизм Copy-on-Write отделяет хранилища массивов, если они разделялись.
Если нужна полная независимость данных, необходимо явно выполнить глубокое копирование: создать новые экземпляры классов и скопировать в них нужные значения. Простое присваивание массива или вызов поверхностного копирования этого не гарантирует.
Выбор класса оправдан, когда объект должен иметь идентичность или совместно изменяемое состояние. Если модель не требует идентичности, часто безопаснее использовать структуру: тогда копирование массива вместе с копированием элементов обеспечивает независимые значения без ручного клонирования ссылочных объектов.
В приложении есть два списка задач: исходный список и времальный список для редактирования. Элементы представлены классами, и разработчик копирует массив перед редактированием. Изменение названия задачи в черновике неожиданно меняет название и в исходном списке.
Вариант с обычным присваиванием массива сохраняет общие экземпляры и не подходит. Вариант с ручным клонированием каждого объекта обеспечивает независимость, но требует определить правила копирования вложенных ссылок и увеличивает сложность.
Вариант с переводом модели задачи в структуру обычно проще: копирование значения делает изменения черновика локальными. Если же задача должна иметь общую идентичность, выбранным решением будет явное глубокое копирование с документированными правилами для вложенных объектов. Это устраняет скрытое разделение состояния и делает границы редактирования предсказуемыми.
Ответ: Не обязательно. Изменение свойства объекта не является изменением структуры массива: меняется объект, на который указывает элемент. Поэтому Swift не обязан отделять хранилища массивов. Если же заменить сам элемент, удалить его или изменить длину массива, может потребоваться отделение хранилища по правилам Copy-on-Write.
let-ссылка на объект элементы массива неизменяемыми?Ответ: Нет. let запрещает переназначить саму ссылку, но не обязательно запрещает изменение состояния объекта, на который она указывает. Для запрета изменения свойств нужен неизменяемый интерфейс объекта или соответствующая архитектура модели; константность ссылки и неизменяемость объекта — разные свойства.
Ответ: Нет. Внешняя структура будет копироваться как значение, но её ссылочное свойство может продолжать указывать на один общий объект. Тогда копии структур независимы на уровне собственных полей, однако изменения общего ссылочного поля всё ещё могут быть видны в обеих копиях. Для полной value semantics все значимые вложенные компоненты также должны быть значениями либо должны явно копироваться.