class — 개념, 핵심 개념 및 Swift에서의 작동 원리

저자: IT Sectr 게시일: 2026-06-17 읽는 시간: 8 분

Class는 Swift 언어의 참조 타입(reference type)으로, 인스턴스가 할당 시 복사되지 않고 참조로 전달됩니다. 구조체와 달리 클래스는 상속, 초기화 해제 및 메모리 관리를 위한 자동 참조 카운팅 ARC를 지원합니다. Swift Programming Language Guide, 2026에 따르면, Apple의 UI 프레임워크(UIKit, AppKit)로 작업하고 객체의 공유 정체성이 필요한 패턴을 구현하려면 class가 필요합니다. class와 struct 사이의 선택은 Swift의 주요 아키텍처 결정 중 하나입니다.

핵심 포인트

  • Class — 변수가 값 자체가 아니라 힙의 객체에 대한 참조를 저장하는 Swift의 참조 타입입니다.
  • 상속 — 클래스는 부모 클래스의 속성과 메서드를 상속받고 override를 사용하여 재정의할 수 있습니다.
  • ARC — 자동 참조 카운팅은 객체에 대한 강한 참조가 없을 때 메모리를 해제합니다.
  • Deinit — 리소스를 정리하기 위해 객체가 해제되기 전에 호출되는 특별한 메서드입니다.
  • 정체성 — === 및 !== 연산자는 두 변수가 동일한 클래스 인스턴스를 참조하는지 확인합니다.

Swift에서 class란?

Class — 속성과 메서드를 상속 및 동적 디스패치 지원과 함께 단일 엔터티로 그룹화하는 Swift의 복합 참조 타입입니다. struct와 달리 클래스 인스턴스는 에 생성되며, 변수는 데이터 자체가 아니라 이 인스턴스에 대한 참조를 저장합니다.

클래스 변수를 다른 변수에 할당하면 둘 다 메모리에서 동일한 객체를 참조합니다. 한 참조를 통한 변경 사항은 다른 참조를 통해 표시됩니다 — 이는 참조 타입의 기본 속성이며, 위임, 관찰 및 공유 상태 패턴에서 사용됩니다.

Apple Swift 문서에 따르면, 모든 UI 구성 요소가 UIView와 UIViewController에서 상속되는 UIKit 및 AppKit으로 작업하는 유일한 방법은 클래스입니다. 또한 객체 정체성(하나의 객체에 대한 두 개의 참조)과 제어된 수명이 필요한 패턴을 구현하려면 클래스가 필요합니다.

참조 타입으로서의 class

참조 타입 의미론 — 클래스의 주요 속성입니다. 클래스를 새 변수에 할당할 때 Swift는 데이터가 아니라 참조를 복사합니다. 동일한 인스턴스를 참조하는 모든 변수는 현재 상태를 보고 수정할 수 있습니다. 이 동작은 각 변수가 독립적인 복사본을 얻는 값 타입과 근본적으로 다릅니다.

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.method()를 호출해야 합니다 — 이는 컴파일러 요구 사항입니다.

Final 클래스

class 앞의 키워드 final은 상속을 방지합니다. 컴파일러는 정적 디스패치를 통해 final 클래스의 메서드 호출을 최적화하여 성능을 향상시킬 수 있습니다. 확장할 의도가 없는 클래스에는 final을 사용하세요 — 의도를 문서화하고 코드를 빠르게 합니다.

swift
// 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레벨 이상)는 유지 관리와 테스트를 복잡하게 만듭니다. 상속 없이 기능을 재사용하려면 확장 및 프로토콜 지향 프로그래밍과 함께 프로토콜을 사용하세요 — Apple이 깊은 클래스 계층 구조의 대안으로 권장하는 접근 방식입니다.

초기화 해제와 메모리 관리

Swift는 클래스 메모리 관리를 위해 ARC(자동 참조 카운팅)를 사용합니다. 각 클래스 인스턴스에는 강한 참조 카운터가 있습니다. 새로운 강한 참조가 생성되면 카운터가 증가하고, 소멸되면 감소합니다. 카운터가 0에 도달하면 메모리가 해제됩니다.

Deinit

Deinit — 클래스 인스턴스가 해제되기 전에 자동으로 호출되는 메서드입니다. 리소스를 해제합니다: 파일을 닫고, 알림 구독을 취소하고, 타이머를 중지합니다. Deinit은 클래스에서만 사용할 수 있습니다 — 구조체와 열거형에는 없습니다.

약한 참조와 미소유 참조

강한 참조 순환(retain cycles)을 방지하기 위해 Swift는 weak 및 unowned 참조를 제공합니다. Weak는 객체가 해제될 때 자동으로 nil이 되는 옵셔널 참조입니다. Unowned는 옵셔널이 아니지만 현재 컨텍스트보다 오래 살 것이 보장된 객체를 참조합니다. 일반적인 retain cycle은 부모-자식 관계에서 발생합니다: 자식이 부모에 대한 강한 참조를 보유합니다.

swift
// 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 vs Struct: 주요 차이점

class와 struct 사이의 선택은 성능, 스레드 안전성 및 API 설계에 영향을 미치는 아키텍처 결정입니다. 각 경우에 올바른 결정을 내리는 데 도움이 되도록 주요 차이점 표를 고려하세요.

특성classstruct
타입참조 타입값 타입(복사)
메모리힙 + ARC스택 / 인라인
상속지원(단일 부모)지원 안 함
Deinit있음없음
정체성 (===)지원지원 안 함
Mutating필요 없음(항상 mutating)mutating에서만
Memberwise init생성되지 않음자동 생성
스레드 안전성보장되지 않음(공유 상태)보장됨(복사)

공유 정체성(코드의 여러 부분이 하나의 객체로 작업), 상속 또는 Objective-C 런타임과의 상호 작용이 필요할 때 클래스를 사용하세요. 그 외 모든 경우에는 구조체가 선호됩니다 — 더 빠르고, 멀티스레드 코드에서 안전하며, 메모리 관리가 필요하지 않습니다.

Swift에서 class를 사용해야 할 때

Apple이 기본적으로 struct를 사용할 것을 권장함에도 불구하고, 여러 특정 시나리오에서는 클래스가 필요합니다. 실제 예제와 함께 각각을 살펴보겠습니다.

UIKit 및 AppKit 구성 요소

iOS 및 macOS의 모든 UI 구성 요소는 UIView(iOS) 또는 NSView(macOS)에서 상속받는 클래스입니다. UIViewController를 구조체로 대체할 수 없습니다 — 리소스를 해제하기 위해 상속과 deinit이 필요합니다. UIKit으로 작업할 때는 컨트롤러, 뷰 및 해당 델리게이트에 클래스를 사용하세요.

싱글톤 및 공유 상태

싱글톤 패턴(전체 응용 프로그램에 대한 하나의 클래스 인스턴스)은 참조 의미론이 필요합니다. 관리자: NetworkManager, SettingsManager, AnalyticsService — 일반적으로 공유 정적 속성이 있는 클래스로 구현됩니다. 구조체는 각 복사본이 독립적인 인스턴스가 되므로 적합하지 않습니다.

의존성 주입 및 참조 객체

객체가 유일한 진실 공급원이어야 하고 모듈 간에 참조로 전달되어야 하는 경우 — class를 사용하세요. 이는 한 곳에서 객체를 변경하는 것이 모든 종속 구성 요소에 표시되어야 하는 상태 관리에 적용됩니다. SwiftUI의 ObservableObject의 경우 클래스가 필수입니다.

swift
// ObservableObject — SwiftUI에 class 필요
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를 선택하세요.

자주 묻는 질문

Swift에서 class란 무엇인가요?

Class는 상속, 초기화 해제 및 메모리 관리를 위한 ARC를 지원하는 Swift의 참조 타입입니다. 클래스 인스턴스는 힙에 저장되며 변수는 객체의 복사본이 아닌 참조를 포함합니다.

Swift에서 class와 struct의 차이점은 무엇인가요?

Class — 참조 타입(참조로 전달됨), 상속 및 deinit을 지원합니다. Struct — 값 타입(복사됨), 상속을 지원하지 않지만 프로토콜을 구현하고 memberwise init을 자동으로 받습니다. Swift는 기본 타입으로 struct를 권장합니다.

Swift에서 ARC란 무엇인가요?

ARC(자동 참조 카운팅) — Swift 클래스의 메모리 관리 메커니즘입니다. 각 인스턴스에는 강한 참조 카운터가 있습니다. 카운터가 0에 도달하면 메모리가 해제됩니다. weak 및 unowned 참조는 객체 간의 retain cycles을 방지합니다.

Swift에서 deinit이란 무엇인가요?

Deinit — 메모리가 해제되기 전에 자동으로 호출되는 클래스 메서드입니다. 파일 닫기, 알림 구독 취소 및 기타 정리 작업에 사용됩니다. Deinit은 클래스에서만 사용할 수 있으며 구조체에는 없습니다.

Swift에서 class는 언제 사용해야 하나요?

UIKit/AppKit UI 구성 요소, 싱글톤, SwiftUI의 ObservableObject, 공유 정체성이 있는 객체(델리게이트, 옵저버) 및 Objective-C 런타임으로 작업할 때 class를 사용하세요. 데이터 모델, DTO 및 구성에는 struct가 선호됩니다.

요약

  • Class는 참조 전달 의미론을 가진 Swift의 참조 타입입니다: 하나의 객체를 가리키는 모든 변수는 현재 상태를 보고 수정할 수 있습니다.
  • ARC는 강한 참조 카운팅을 통해 클래스 메모리를 관리합니다; weak와 unowned는 부모-자식 관계 및 클로저에서 retain cycles을 방지합니다.
  • 상속을 통해 클래스는 부모의 동작을 재사용하고 재정의할 수 있지만, 깊은 계층 구조(5레벨 이상)는 코드 유지 관리를 복잡하게 만듭니다.
  • Deinit은 객체가 해제될 때 실행되며 리소스(파일, 타이머, NotificationCenter 구독)를 해제하는 데 필요합니다.
  • UIKit 및 AppKit은 모든 UI 구성 요소(UIView, UIViewController, 해당 델리게이트 및 데이터 소스)에 클래스가 필요합니다.
  • SwiftUI의 ObservableObject — SwiftUI는 @Published 및 @StateObject를 참조로 변경 사항을 추적하므로 class가 필수입니다.
  • Apple은 새 데이터 타입에 기본 타입으로 struct를 권장합니다 — 정체성, 상속 또는 Objective-C 통합이 필요한 경우에만 class를 사용하세요.

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기