Классы и структуры в программировании на Swift: что выбрать?

В чем разница между классами и структурами? Ведь они по сути похожи друг на друга. По умолчанию лучше использовать структуры, но почему? В каких случаях лучше использовать классы? В этой статье мы детально рассмотрим структуры и классы и разберем особенности их применения.

Структуры и классы

Сначала давайте посмотрим, что общего между классами и структурами:

  • Они могут определять свойства и методы.
  • Они могут определять сабскрипты.
  • Они могут определить инициализаторы с помощью функции init().
  • Они могут использовать расширения.
  • Они могут соответствовать протоколам.

Также классы поддерживают дополнительные возможности, которые не имеют структуры:

  • Классы могут наследоваться от другого класса.
  • Классы могут содержать деинициализаторы.
  • Классы являются ссылочными типами, а структуры являются значимыми типами.

В значимых типах, когда вы копируете значение, каждый экземпляр сохраняет уникальную копию данных. Если вы измените один экземпляр, другой экземпляр не изменится.

В ссылочных типах, когда вы копируете значение, копируется ссылка на область в памяти, в которой хранится данное значение. Каждый экземпляр совместно использует данные. Когда вы меняете один экземпляр, другой также меняется.

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

Когда стоит использовать структуры?

По умолчанию рекомендуется использовать структуры. Структуры также полезны в следующих сценариях:

  • Используйте структуры для простых типов данных. Воспринимайте их как простые базы данных, которые вы можете использовать в своем коде, например NewsItem, Task или User. Поскольку они четко определены и часто не нуждаются в сложных отношениях между объектами.
  • В многопоточной среде, например, с подключением к базе данных в другом потоке, структуры более безопасны. и могут быть безопасно скопированы из одного потока в другой. Классы не имеют присущей им безопасности, если только они не намеренно сделаны поточно-ориентированными.
  • Когда свойства структуры в основном являются значимыми типами, например String, имеет смысл обернуть их в структуру вместо класса.

Использование структур имеет дополнительное преимущество: вам проще анализировать изменения данных в вашем коде. Когда тип является структурой, вы можете быть уверены, что никакая другая часть вашего кода не сможет удерживать ссылку на объект. То есть структура не может быть изменена какой-либо другой частью вашего кода.

struct NewsItem {
    var title: String = ""
    var url: String = ""
}
 
var item = NewsItem()
item.title = "Сравнение классов и структур в Swift"
item.url = "https://developer.apple.com/documentation/"
 
print(item)
// NewsItem(title: "Сравнение классов и структур в Swift", url: "https://developer.apple.com/documentation/")

Когда стоит использовать классы?

Рекомендуется использовать класс, если вам нужны его характерные особенности. Как отмечалось ранее, у классов есть несколько дополнительных характеристик, которых нет у структур:

  • Классы могут наследоваться друг от друга.
  • Классы могут быть деинициализированы.
  • Классы поставляются со встроенным понятием идентичности , потому что они являются ссылочными типами. С помощью оператора идентичности === вы можете проверить, ссылаются ли два экземпляра класса на один и тот же объект.

Рядом со ссылочным типом значений наследование является наиболее важным различием между классом и структурой. С помощью классов вы можете четко определить родительско-дочернюю связь между подклассом и суперклассом.

Несколько примеров:

  • MyViewController наследуется от UIViewController.
  • MyTableViewController наследуется от InfiniteTableViewController для создания «бесконечной прокрутки», который в свою очередь наследуется от UITableViewController.
  • Классы Car и Bike наследуются от Vehicle, потому что оба они используют один и тот же «базовый» набор характеристик, что numberOfWheels и speed.

В двух последних примерах есть опасность: вы можете получить целую кучу унаследованных классов, у каждого из которых есть свои методы. В этом случае может иметь смысл использовать протокольно-ориентированное программирование.

Лучше использовать классы в следующих сценариях:

  • Когда копирование экземпляров не имеет смысла, например, Window или UIViewController. Копировать окно приложения не имеет смысла, поскольку одновременно активно только один окно, и зачастую не имеет смысла также копировать View Controller – вы просто создаете новый.
  • Когда время жизни экземпляра связано с внешними эффектами, например, для DatabaseConnection или TemporaryFile. Не имеет смысла создавать две копии ссылки на файл, если они оба ссылаются на одни и те же данные.
  • Когда экземпляры просто являются проводниками для нешних состояний, например, CGContext. Иногда вам нужен вспомогательный класс или класс-оболочка, чтобы добиться цели. В этих случаях класс является всего лишь каналом, который передает информацию, и не имеет смысла создавать его копию.
Читайте также:
Добавить комментарий

Ваш адрес email не будет опубликован.