iOS Development Guide

Value Type vs Reference Type

Swift의 값 타입과 참조 타입 차이를 저장 위치보다 동작 방식 중심으로 정리한 문서다. 핵심은 `복사 semantics`, `identity`, `shared mutable state`, `동시성 안전성` 차이를 같이 보는 것이다.

Swift core concept Practical engineering emphasis Knowledge items #1, #17, #30, #80
학습 날짜

2026-04-09

Why This Work Exists

값 타입은 스택, 참조 타입은 힙이라고만 외우면 실무에서 자꾸 틀린다. 진짜 중요한 차이는 “복사처럼 행동하느냐”, “같은 객체를 공유하느냐”다.

Scope / Non-scope

  • value semantics와 reference semantics 차이
  • copy-on-write의 의미
  • identity와 equality 차이
  • shared mutable state와 동시성 안전성 관점
  • 실제 ABI/메모리 배치 세부 구현은 깊게 다루지 않는다

As-is

흔한 오해는 `struct = 무조건 스택`, `class = 무조건 힙`, `값 타입은 복사 비용이 크다`, `참조 타입은 빠르다`처럼 단순화하는 것이다.

To-be

더 정확한 이해는 이렇다. 값 타입은 복사된 값처럼 동작하고, 참조 타입은 같은 객체를 공유한다. 실무적으로는 저장 위치보다 복사 semantics, identity, 공유 상태, ARC, 동시성 안전성이 더 중요하다.

What The Developer Must Understand Next

핵심 요약

값 타입과 참조 타입의 가장 중요한 차이는 스택/힙보다 `복사처럼 행동하느냐`, `같은 객체를 공유하느냐`다.

API / Data Contract

  • value type: `struct`, `enum`, `Int`, `Array`, `Dictionary` 등
  • reference type: `class`
  • 값 타입도 내부 최적화로 copy-on-write를 쓸 수 있다
  • 참조 타입은 ARC와 객체 생명주기 관리가 중요하다

Risks And Decisions Needed

  • `값 타입 = 항상 스택`으로만 외우면 틀릴 수 있다.
  • `class let`은 참조만 고정할 뿐 내부 mutable state는 바뀔 수 있다.
  • 값 타입이라도 큰 데이터를 자주 복사하면 비용을 봐야 한다.
  • 참조 타입은 shared mutable state와 retain cycle 문제를 같이 고려해야 한다.

Class Diagram

classDiagram class ValueType { +copySemantics() +independentMutation() } class ReferenceType { +sharedIdentity() +sharedMutationRisk() } class Identity { +sameObject() } class SharedMutableState { +concurrencyRisk() } ValueType --> SharedMutableState : reduces ReferenceType --> Identity : emphasizes ReferenceType --> SharedMutableState : may create

Sequence Diagram

sequenceDiagram participant A as var a participant B as var b participant Obj as Shared Object rect rgb(240,253,244) Note over A,B: Value type A->>B: assign value B->>B: mutate B-->>A: original unaffected end rect rgb(245,248,255) Note over A,Obj: Reference type A->>Obj: hold reference B->>Obj: hold same reference B->>Obj: mutate Obj-->>A: observed through same object end

Flowchart

flowchart LR A["Need model / state type"] --> B{"Shared mutable state needed?"} B -->|"No"| C["Prefer value type"] B -->|"Yes"| D{"Single shared identity matters?"} D -->|"Yes"| E["Reference type may fit"] D -->|"No"| F["Reconsider immutable value model"]

Detailed Reading: Copy Semantics

var a = [1, 2, 3]
var b = a
b.append(4)

위 코드는 value semantics를 보여 준다. `b`를 바꿔도 `a`는 그대로다. 다만 `Array`는 성능 최적화를 위해 처음부터 전체 메모리를 복사하지 않고, 실제 수정 시점에 복사하는 copy-on-write를 사용한다.

즉 겉보기 동작은 “복사된 값”인데, 내부 구현은 “수정 전까지 저장소를 잠깐 공유”할 수 있다. 그래서 값 타입처럼 행동하지만 내부 구현은 더 복잡할 수 있다.

Detailed Reading: Identity

final class Box {
    var value: Int
    init(value: Int) { self.value = value }
}

let a = Box(value: 1)
let b = a
b.value = 2

여기서는 `a`와 `b`가 같은 객체를 본다. 이때 중요한 것은 값이 아니라 “같은 인스턴스인가”라는 identity다.

Shared Mutable State

같은 객체를 여러 곳이 공유하고, 그 객체의 내부 상태를 바꿀 수 있으면 shared mutable state가 생긴다. 이건 참조 타입이 자연스럽게 만들기 쉬운 구조다.

이런 구조는 캐시, 세션, 매니저 객체처럼 하나의 실체를 여러 곳이 함께 바라봐야 할 때 유리하다. 대신 동시에 접근하면 data race와 동기화 문제가 생길 수 있다.

Concurrency Safety

값 타입은 각자가 복사본을 들고 다루기 쉬워 동시성에서 유리하다. 반면 참조 타입은 같은 객체를 공유하므로 actor, lock, serial queue 같은 보호 장치가 더 자주 필요하다.

그래서 Swift Concurrency 문맥에서 value semantics가 자주 강조되고, shared mutable state가 남는 경우 actor가 등장한다.

QA Checklist

  • `스택 vs 힙`만으로 설명을 끝내지 않았는지 확인한다.
  • copy semantics와 identity 차이를 분리해서 설명했는지 확인한다.
  • copy-on-write를 값 타입의 동작과 구현 차이로 설명했는지 확인한다.
  • shared mutable state와 동시성 안전성을 같이 묶어 설명했는지 확인한다.