Class — це тип-посилання (reference type) у мові Swift, екземпляри якого передаються за посиланням, а не копіюються при присвоєнні. На відміну від структур, класи підтримують успадкування, деініціалізацію та автоматичний підрахунок посилань ARC для керування пам'яттю. За даними Swift Programming Language Guide, 2026, class необхідний для роботи з UI-фреймворками Apple (UIKit, AppKit) та реалізації патернів, що потребують спільної ідентичності об'єкта. Вибір між class та struct — одне з ключових архітектурних рішень у Swift.
Головне
Class — це складовий тип-посилання у Swift, який групує властивості та методи в єдину сутність із підтримкою успадкування та динамічної диспетчеризації. На відміну від struct, екземпляр класу створюється в купі (heap), а змінна зберігає посилання на цей екземпляр, а не самі дані.
Коли ви присвоюєте змінну класу іншій змінній, обидві посилаються на той самий об'єкт у пам'яті. Зміни через одне посилання видимі через інше — це фундаментальна властивість типів-посилань, яка використовується в патернах делегування, спостереження та спільного стану.
За даними документації Apple Swift, класи — єдиний спосіб працювати з UIKit та AppKit, де всі UI-компоненти успадковуються від UIView та UIViewController. Крім того, класи необхідні для реалізації патернів, що потребують ідентичності об'єкта (два посилання на один об'єкт) та контрольованого часу життя.
Семантика типу-посилання — ключова властивість класів. При присвоєнні класу новій змінній Swift копіює посилання, а не дані. Всі змінні, що посилаються на один екземпляр, бачать його поточний стан і можуть його змінювати. Ця поведінка принципово відрізняється від типів-значень, де кожна змінна отримує незалежну копію.
// Приклад семантики типу-посилання
class User {
var name: String
init(name: String) { self.name = name }
}
let user1 = User(name: "Alice")
let user2 = user1 // user2 — те саме посилання
user2.name = "Bob"
print(user1.name) // "Bob" — змінено через user2!
// Перевірка ідентичності оператором ===
print(user1 === user2) // true — той самий об'єкт
Оператори === (ідентичність) та !== перевіряють, чи посилаються дві змінні на один і той самий екземпляр класу. Це відрізняється від == (рівність), яке порівнює значення властивостей. Оператор === недоступний для struct — типи-значення не мають ідентичності.
Успадкування — механізм, за якого клас може перейняти властивості та методи батьківського класу. У Swift клас може успадковувати лише від одного батька (одинарне успадкування), але може реалізовувати безліч протоколів. Ключове слово override дозволяє перевизначити успадкований метод або властивість.
Будь-який клас, який не успадковує від іншого класу, автоматично стає базовим (не плутати з NSObject). Підклас вказує батька через двокрапку після свого імені. Якщо підклас перевизначає метод батька, він зобов'язаний викликати super.метод() для збереження батьківської поведінки — це обов'язкова вимога компілятора.
Ключове слово final перед class забороняє успадкування. Компілятор може оптимізувати виклики методів final-класу через статичну диспетчеризацію, що підвищує продуктивність. Використовуйте final для класів, які не призначені для розширення — це документує ваш намір і прискорює код.
// Приклад успадкування класів у Swift
class Vehicle {
var speed: Double = 0
func description() -> String {
"Speed: \(speed) km/h"
}
}
// Car успадковує Vehicle
class Car: Vehicle {
var brand: String = "Unknown"
override func description() -> String {
"\(brand) - \(speed) km/h"
}
}
// Final клас — запобігає успадкуванню
final class ElectricCar: Car {
var batteryLevel: Double = 100
}
let tesla = ElectricCar()
tesla.brand = "Tesla"
tesla.speed = 120
print(tesla.description()) // "Tesla - 120.0 km/h"
Успадкування класів — потужний, але відповідальний механізм. Глибока ієрархія (5+ рівнів) ускладнює підтримку та тестування. Для повторного використання функціональності без успадкування використовуйте протоколи з extension та протокольно-орієнтоване програмування — підхід, який Apple просуває як альтернативу глибоким class-ієрархіям.
Swift використовує ARC (Automatic Reference Counting) для керування пам'яттю класів. Кожен екземпляр класу має лічильник сильних посилань. При створенні нового сильного посилання лічильник збільшується; при знищенні — зменшується. Коли лічильник досягає нуля, пам'ять звільняється.
Deinit — метод, який викликається автоматично перед звільненням екземпляра класу. У ньому звільняють ресурси: закривають файли, відписуються від сповіщень, зупиняють таймери. Deinit є тільки у класів — у структур та перерахувань його немає.
Для запобігання циклам сильних посилань (retain cycles) Swift надає weak та unowned посилання. Weak — опціональне посилання, яке автоматично стає nil при звільненні об'єкта. Unowned — неопціональне, але посилається на об'єкт, який гарантовано живе довше поточного контексту. Типовий retain cycle виникає у відношенні батько-дитина: дитина зберігає сильне посилання на батька.
// Приклад ARC та слабкого посилання
class Parent {
var name: String
var child: Child?
init(name: String) { self.name = name }
deinit { print("\(name) звільнено") }
}
class Child {
var name: String
weak var parent: Parent? // weak запобігає retain cycle
init(name: String) { self.name = name }
deinit { print("\(name) звільнено") }
}
var parent: Parent? = Parent(name: "Anna")
parent?.child = Child(name: "Mia")
parent?.child?.parent = parent
parent = nil // Обидва об'єкти звільнено!
// Без weak створив би retain cycle
Завжди використовуйте weak для посилань від дочірнього об'єкта до батьківського та для списків захоплення в замиканнях. Unowned використовуйте лише коли впевнені, що об'єкт переживе поточний контекст — неправильне використання unowned може призвести до краху при зверненні до звільненої пам'яті.
Вибір між class та struct — архітектурне рішення, яке впливає на продуктивність, безпеку потоків та дизайн API. Розгляньмо таблицю ключових відмінностей, яка допоможе прийняти правильне рішення в кожному конкретному випадку.
| Характеристика | class | struct |
|---|---|---|
| Тип | Тип-посилання | Тип-значення (копія) |
| Пам'ять | Купа (heap) + ARC | Стек / inlined |
| Успадкування | Підтримує (один батько) | Не підтримує |
| Deinit | Є | Немає |
| Ідентичність (===) | Підтримує | Не підтримує |
| Mutating | Не потрібно (завжди mutating) | Тільки з mutating |
| Memberwise init | Не генерується | Генерується автоматично |
| Безпека потоків | Не гарантована (спільний стан) | Гарантована (копіювання) |
Використовуйте класи, коли потрібна спільна ідентичність (кілька частин коду працюють з одним об'єктом), успадкування або взаємодія з Objective-C runtime. Для всього іншого переважні структури — вони швидші, безпечніші в багатопотоковому коді та не потребують керування пам'яттю.
Незважаючи на рекомендацію Apple використовувати struct за замовчуванням, класи необхідні в кількох конкретних сценаріях. Розгляньмо кожен із практичними прикладами.
Всі UI-компоненти в iOS та macOS — класи, які успадковують від UIView (iOS) або NSView (macOS). Ви не можете замінити UIViewController на структуру — він потребує успадкування та deinit для звільнення ресурсів. При роботі з UIKit використовуйте класи для контролерів, view та їхніх делегатів.
Патерн Singleton (один екземпляр класу на весь застосунок) потребує семантики посилань. Менеджери: NetworkManager, SettingsManager, AnalyticsService — зазвичай реалізуються як класи з shared static властивістю. Структури не підходять, оскільки кожна копія буде незалежним екземпляром.
Коли об'єкт має бути єдиним джерелом істини та передається між модулями за посиланням — використовуйте class. Це стосується керування станом, де зміна об'єкта в одному місці має бути видимою у всіх залежних компонентах. Для ObservableObject у SwiftUI класи обов'язкові.
// ObservableObject — class обов'язковий для SwiftUI
import SwiftUI
class AppViewModel: ObservableObject {
@Published var isLoggedIn: Bool = false
@Published var username: String = ""
func login(user: String) {
isLoggedIn = true
username = user
}
}
// Використання у SwiftUI View
struct ContentView: View {
@StateObject var viewModel = AppViewModel()
var body: some View {
Text(viewModel.isLoggedIn ? "Ласкаво просимо" : "Увійти")
}
}
Правило: якщо об'єкт повинен мати ідентичність (два посилання -> один об'єкт), бути єдиним екземпляром або працювати з UIKit/Objective-C — вибирайте class. Якщо об'єкт просто містить дані — вибирайте struct.
Поширені запитання
Class — це тип-посилання у Swift, який підтримує успадкування, деініціалізацію та ARC для керування пам'яттю. Екземпляри класів зберігаються в купі, а змінні містять посилання на об'єкт, а не його копію.
Class — тип-посилання (передається за посиланням), підтримує успадкування та deinit. Struct — тип-значення (копіюється), не підтримує успадкування, але реалізує протоколи та отримує memberwise init автоматично. Swift рекомендує struct як тип за замовчуванням.
ARC (Automatic Reference Counting) — механізм керування пам'яттю для класів Swift. Кожен екземпляр має лічильник сильних посилань. При обнулінні лічильника пам'ять звільняється. Weak та unowned посилання запобігають retain cycles між об'єктами.
Deinit — метод класу, який викликається автоматично перед звільненням його пам'яті. Використовується для закриття файлів, відписки від сповіщень та інших завершальних операцій. Deinit є тільки у класів — у структур його немає.
Використовуйте class для UI-компонентів UIKit/AppKit, singleton, ObservableObject у SwiftUI, об'єктів зі спільною ідентичністю (delegate, observer) та при роботі з Objective-C runtime. Для моделей даних, DTO та конфігурацій переважна struct.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.