Представьте, что функции передали экземпляр класса: почему изменение его свойства видно снаружи, а переназначение локальной ссылки на другой экземпляр — нет?
В Swift экземпляр класса передаётся в функцию по значению, но этим значением является копия ссылки на тот же объект. Поэтому изменение свойства затрагивает общий экземпляр и видно вызывающему коду, а переназначение локальной ссылки меняет только локальную переменную функции.
Модель ссылочных типов нужна для представления объектов с общей идентичностью и изменяемым состоянием. Несколько частей программы могут обращаться к одному экземпляру, не создавая копии всего его состояния.
Swift сочетает ссылочные и значимые типы. Такое разделение позволяет выбирать между независимыми копиями данных и совместным доступом к одному объекту.
Без понимания этой семантики можно ошибочно ожидать, что передача класса в функцию либо полностью копирует объект, либо позволяет функции заменить объект у вызывающего кода.
На самом деле копируется только значение ссылки. Изменение состояния общего объекта распространяется на всех его владельцев, а изменение самой локальной ссылки наружу не передаётся. Это влияет на проектирование API, тестируемость и потокобезопасность.
Параметры функций в Swift по умолчанию являются локальными неизменяемыми привязками. Для класса такая привязка содержит ссылку на объект, поэтому через неё можно менять его изменяемые свойства, хотя саму привязку нельзя переназначить.
После передачи profile и параметр profile ссылаются на один объект. Операция изменения name меняет этот объект, поэтому после возврата напечатается Новый.
Переменная local сначала также ссылается на исходный объект, но затем получает ссылку на новый экземпляр. Это переназначение не меняет переменную profile вне функции. Прямое переназначение параметра без создания локальной переменной обычно невозможно, поскольку параметры являются неизменяемыми привязками.
Важно отличать изменение объекта от изменения ссылки. var у свойства разрешает менять состояние объекта, но не превращает передачу параметра в передачу ссылки на переменную вызывающего кода.
У ссылочной семантики есть компромисс: она удобна для совместного состояния, но создаёт неявные побочные эффекты. Если нужна независимая копия, её следует явно создать; простое присваивание экземпляра класса копию объекта не создаёт.
Время жизни объекта управляется ARC: объект остаётся в памяти, пока на него существуют сильные ссылки. ARC не меняет правило о том, что переназначение локальной ссылки не заменяет ссылку вызывающего кода.
В приложении есть объект состояния профиля, который передаётся нескольким сервисам. Один сервис должен обновить имя профиля, а другой — подготовить альтернативную версию для предварительного просмотра.
Вариант с классом позволяет обоим сервисам обращаться к одному состоянию и недорого передавать ссылку. Минус — обновление в одном сервисе сразу видно остальным, а порядок изменений может стать важным.
Вариант со структурой даёт независимое значение при присваивании, что уменьшает неявные побочные эффекты. Однако для большой модели или намеренно общего состояния это может потребовать явного возврата обновлённого значения и дополнительной координации.
Если изменение профиля должно быть общим, оправдан класс с чётко определёнными границами мутаций. Для предварительного просмотра лучше явно создавать отдельную копию данных, а не рассчитывать на переназначение локальной ссылки: это делает намерение очевидным и предотвращает случайное изменение общего объекта.
1. Можно ли считать присваивание экземпляра класса его копированием?
Нет. Присваивание создаёт ещё одну ссылку на тот же объект. Изменение его изменяемого свойства через любую из этих ссылок будет видно через остальные. Независимая копия требует отдельной логики копирования, например специального метода или иного проектного решения.
2. Что изменится, если свойство объекта объявлено как неизменяемое?
Если свойство объявлено через let, изменить его после инициализации нельзя независимо от того, сколько ссылок у объекта. Ссылочная семантика отвечает за общую идентичность объекта, но не отменяет правила доступности и изменяемости его свойств.
3. Передаст ли inout возможность заменить экземпляр класса у вызывающего кода?
Да, если параметр класса передан через inout, функция получает возможность изменить значение переменной вызывающего кода, включая замену ссылки на другой экземпляр. Это отличается от обычной передачи класса: без inout функция может менять общий объект, но не может заменить внешнюю переменную, содержащую ссылку.