상세 컨텐츠

본문 제목

iOS프로그래밍_7주차_열거형(enum), 구조체(struct)클래스vs.구조체vs. 열거형

2026년도 1학기/iOS프로그래밍

by 멈뭉밈 2026. 4. 20. 14:04

본문

(시험에 나옴) .을 찍어서 접근하는게 열거형의 접근 방식이다 (.찍어서 접근하면 열거형 쓰는거다)

 

 

 

 

대표적으로 enum(열거형)을 지원하는 주요 언어들을 카테고리별로 정리


1. 정적 타입 언어 (클래식 enum 지원)

우리가 흔히 아는 “진짜 enum” 느낌

  • C
  • C++
  • Java
  • C#
  • Kotlin
  • Swift
  • Go (iota 기반 enum 패턴)
  • Rust
  • D
  • Zig

2. 함수형 / 현대 언어 (강력한 enum or ADT)

단순 enum보다 더 강력 (패턴 매칭 가능)

  • Scala
  • Haskell
  • OCaml
  • F#
  • Elm

이쪽은 enum이라기보다 “Algebraic Data Type (ADT)” 형태


3. 스크립트 / 동적 언어 (유사 enum 또는 공식 지원)

예전엔 없었는데 요즘 많이 생김

  • Python (Enum 클래스)
  • TypeScript
  • JavaScript (객체로 흉내)
  • PHP (8.1부터 enum)
  • Ruby (심볼/enum gem)
  • Lua (테이블로 구현)

4. 시스템 / 저수준 / 특수 언어

임베디드, 성능 중심

  • Ada
  • Nim
  • Crystal
  • V

5. 데이터/쿼리 언어 (의외로 있음)

  • SQL (ENUM 타입 – MySQL 등)

핵심 정리 (중요)

  • enum은 사실 거의 모든 “현대 언어”가 지원한다고 보면 됨
  • 다만 형태가 다름:
    • C/Java → 단순 값 집합
    • Rust/Swift → 강력한 타입 시스템
    • JS/Python → 객체 기반 흉내 or 클래스

💡한 줄 정리

“enum 없는 언어가 더 드물다” 수준이라고 보면 됨

 

 


 

enum Compass {
    case North
    case South
    case East
    case West
}
//var x : Compass // Compass형 인스턴스 x
print(Compass.North) // North
var x = Compass.West
print(type(of:x)) // Compass
x = .East //Compass.East 와 같음
print(x) // East

 

 

열거형 변수는 한 번 정의한 다음에는 이름을 쓰지 않아도 된다.

.East 는 Compass가 생략된 것이다.

이미 정의를 해둬서 컴파일러가 알고 있기 때문에 생략할 수 있다.

 

 

enum Compass {
    case North
    case South
    case East
    case West
}
var direction : Compass
direction = .South
switch direction { //switch의 비교값이 열거형 Compass
case .North: //direction이 .North이면 "북" 출력
    print("북")
case .South:
    print("남")
case .East:
    print("동")
case .West:
    print("서") //모든 열거형 case를 포함하면 default 없어도 됨
}

위와 같이 switch 문에서도 사용할 수 있다.

 

열거형에 멤버에 접근할 때는 .을 찍으면 자동으로 나온다.

 

enum Week {
    case Mon,Tue,Wed,Thur,Fri,Sat,Sun
    func printWeek() { //메서드도 가능
        switch self {
        case .Mon, .Tue, .Wed, .Thur, .Fri:
            print("주중")
        case .Sat, .Sun:
            print("주말")
        }
    }
}
Week.Sun.printWeek()

이런식으로 메서드도 열거형에서 만들 수 있음

 

 

enum Color: Int { //원시값(rawValue) 지정
    case red
    case green = 2
    case blue
}
print(Color.red) //red
print(Color.blue)
print(Color.green)
print(Color.red.rawValue) //0
print(Color.blue.rawValue)
print(Color.green.rawValue)

red

blue

green

0

3

2

 

 

enum Week: String {
    case Monday = "월"
    case Tuesday = "화"
    case Wednesday = "수"
    case Thursday = "목"
    case Friday = "금"
    case Saturday //값이 지정되지 않으면 case 이름이 할당됨
    case Sunday // = "Sunday"
}
print(Week.Monday) //Monday
print(Week.Monday.rawValue) //월
print(Week.Sunday)
print(Week.Saturday)
print(Week.Sunday.rawValue)
print(Week.Saturday.rawValue)

Monday

Sunday

Saturday

Sunday

Saturday

 

enum Date {
    case intDate(Int,Int,Int) //(int,Int,Int)형 연관값을 갖는 intDate
    case stringDate(String) //String형 연관값을 값는 stringDate
}
var todayDate = Date.intDate(2025,4,30)
//todayDate = Date.stringDate("2025년 5월 20일") //주석처리하면?
switch todayDate {
case .intDate(let year, let month, let day):
    print("\(year)년 \(month)월 \(day)일")
case .stringDate(let date):
    print(date)
}

2025 4 30

 

 


 

 

public enum Optional<Wrapped> {
    case none
    case some(Wrapped)
}

👉 이건 바로
Swift에서 Optional의 실제 내부 구조


💡 쉽게 말하면

우리가 평소에 쓰는 이거:

var name: String? = "홍길동"

사실은 이렇게 생김:

var name: Optional<String> = .some("홍길동")

또는

var name: Optional<String> = .none

📦 구조 해석

Optional<Wrapped>
  • Wrapped = 실제 값 타입 (예: String, Int)
  • 즉 → “값을 감싸는 타입”

enum case 두 개 의미

case none

값 없음 (nil)

case some(Wrapped)

값 있음 (실제 값 저장)


🔍 실제 동작 예

var num: Int? = 10

내부적으로는:

var num: Optional<Int> = .some(10)

var num: Int? = nil

내부적으로는:

var num: Optional<Int> = .none

왜 enum으로 만들었냐?

값이 있냐 / 없냐를 안전하게 구분하려고

C나 Java처럼 하면:

  • null 때문에 터짐

Swift는:

  • .some(value)
  • .none

두 경우를 강제로 구분하게 만듦


그래서 switch가 가능

if let value = num {
    print(value)
}

이건 사실 내부적으로:

switch num {
case .some(let value):
    print(value)
case .none:
    break
}

이거랑 똑같은 구조야


💥 핵심 요약

  • Optional은 특별한 문법이 아니라
    👉 그냥 enum이다
  • 값이 있으면 .some(value)
  • 없으면 .none
  • ?는 Optional의 축약 문법

🚀 한 줄로 정리

👉 Optional = 값이 있을 수도 있고 없을 수도 있는 enum

 

 


 

전체 코드 다시 보기

let age: Int? = 30 // Optional(30)

switch age {
case .none:
    print("나이 정보가 없습니다.")

case .some(let a) where a < 20:
    print("\(a)살 미성년자입니다")

case .some(let a) where a < 71:
    print("\(a)살 성인입니다")

default:
    print("경로우대입니다")
}

1. age의 실제 모습

let age: Int? = 30

이건 내부적으로:

Optional.some(30)

즉,

  • 값 있음 → .some(30)
  • 값 없음 → .none

2. switch는 어떻게 동작하냐

핵심:

위에서부터 순서대로 “조건이 맞는 case 하나만 실행”


3. 하나씩 매칭 과정

① 첫 번째

case .none:

age는 .some(30)이라서 ❌ (nil 아님)


② 두 번째

case .some(let a) where a < 20:
  • .some(30) → a = 30
  • 조건: 30 < 20 ❌

이것도 실패


③ 세 번째

case .some(let a) where a < 71:
  • .some(30) → a = 30
  • 조건: 30 < 71 

여기서 처음으로 조건이 맞음 → 실행됨

print("30살 성인입니다")

그리고 switch 끝남 (아래 안 내려감)


④ default는?

이미 위에서 매칭됐기 때문에 실행 안 됨


핵심 포인트 3개

1    .some(let a) 의미

Optional에서 값 꺼내는 것

.some(30) → a = 30

2    where의 역할

추가 조건 필터

case .some(let a) where a < 20

=
“값이 있고, 그 값이 20 미만이면”


switch는 하나만 실행됨

조건 맞는 첫 번째 case에서 끝


흐름 한 줄 요약

.some(30) →
→ .none ❌
→ <20 ❌
→ <71 ✅→ 실행 → 끝


결과

30살 성인입니다

진짜 중요한 이해

이 코드는 사실 이렇게 생각하면 쉽다:

if age == nil {
    ...
} else if age < 20 {
    ...
} else if age < 71 {
    ...
} else {
    ...
}

근데 Swift는 Optional이라서
.some, .none으로 나눠서 처리하는 것

 

 


 

 

 

 

구조체

실무/학습에서 자주 쓰이는 struct 지원 언어들


1. 전통적인 struct (C 계열 핵심)

“구조체”의 기본 개념

  • C
  • C++
  • Objective-C

특징

  • 필드(데이터) 묶는 용도
  • C는 메서드 없음, C++은 있음

2. 현대 언어 (값 타입 struct 중요)

요즘 개발에서 많이 쓰는 형태

  • Swift
  • Go
  • Rust
  • Kotlin (data class가 사실상 struct 역할)
  • D
  • Zig

특징

  • 값 타입 (복사됨)
  • 메서드 가능
  • 불변성/안정성 강조

3. .NET / 시스템 언어

  • C# (struct 키워드 존재)

특징

  • 값 타입
  • 클래스와 구분됨 (stack vs heap 개념)

4. 시스템/성능 중심 언어

  • Nim
  • Crystal
  • V

5. 함수형/혼합 언어 (유사 개념)

struct라는 키워드는 없지만 비슷한 개념 존재

  • Scala (case class)
  • Haskell (record)
  • OCaml

struct 없는 대신 대체 개념 사용하는 언어

  • Java → class만 있음
  • JavaScript → 객체(Object)
  • Python → class / dataclass
  • Ruby → class

이런 언어들은
struct 대신 class/객체로 통합해서 사용


핵심 정리

struct는 크게 2가지 스타일로 나뉨:

1.  C 스타일

  • 그냥 데이터 묶음

2. 현대 스타일 (Swift, Rust 등)

  • 값 타입 + 메서드 + 불변성
  • 거의 “가벼운 클래스”

한 줄 요약

struct는 “데이터 묶는 타입”인데, 현대 언어에서는 거의 “값 타입 객체”까지 발전한 개념

 

 

 


 

 

 

 

 

swift 의 기본적인 array 배열형도 구조체와 제네릭 타입으로 만들어졌다.

 


 

 

 

구조체와 클래스의 차이점

구조체는 인스턴스 값 타입, 클래스의 인스턴스는 참조 타입 이다.

구조체는 상속 불가다.

 

 

struct Resolution { //구조체 정의
    var width = 1024 //프로퍼티
    var height = 768
}
let myComputer = Resolution() //인스턴스 생성
print(myComputer.width)

let yourComputer = Resolution(width: 200, height: 300)
print(yourComputer.height)

 

구조체에서는 모든 프로퍼티를 초기화 하는 initializer 가 자동 생성 된다.

클래스에서는 직접 만들어야 한다.

 

 

 


 

 

주석으로 되어 있는게 memberwise init이다.

(중요/시험)1. memberwise initializer

memberwise initializer는
구조체의 모든 프로퍼티를 하나씩 받아서 초기화해주는 기본 생성자

Swift에서는 struct를 만들면, 별도로 생성자를 안 써도 자동으로 만들어준다.


2. 지금 코드 기준으로 보면

struct Resolution {
    var width = 1024
    var height = 768
}

이 구조체를 정의하면 Swift가 내부적으로 이런 생성자를 자동으로 만들어준다:

init(width: Int, height: Int) {
    self.width = width
    self.height = height
}

이게 바로 memberwise initializer 이다.


3. 코드에서의 쓰임새

let yourComputer = Resolution(width: 200, height: 300)

이 부분이 memberwise initializer를 사용한 거다.

  • width에 200
  • height에 300

을 직접 넣어서 객체를 만든 것


4. 기본값이 있는데도 왜 가능한 이유

var width = 1024
var height = 768

이렇게 기본값이 있어도, memberwise initializer는 여전히 생성된다.

그래서 두 가지 방식이 다 가능하다:

Resolution()                    // 기본값 사용
Resolution(width: 200, height: 300)  // 직접 지정

5. 중요한 특징

1) struct에만 자동 생성된다

  • struct → 자동 생성됨
  • class → 자동 생성 안 됨

2) 직접 init을 만들면 사라질 수 있다

struct Resolution {
    var width = 1024
    var height = 768

    init() {
        width = 0
        height = 0
    }
}

이렇게 직접 init을 만들면
기본 memberwise initializer (init(width:height:))는 더 이상 자동 생성되지 않는다.


3) 내부 프로퍼티를 그대로 초기화

이름 그대로:

  • member(프로퍼티)
  • wise(하나씩)

각 프로퍼티를 하나씩 받아서 초기화한다는 의미다.


6. 한 줄 정리

memberwise initializer는
struct의 모든 프로퍼티를 매개변수로 받아 자동으로 초기화해주는 기본 생성자다.

 

 


 

 

 

struct Resolution {
    var width = 1024
    var height = 768
}
class VideoMode {
    var resolution = Resolution()
    var frameRate = 0.0
}
let myVideo = VideoMode()
print(myVideo.resolution.height, myVideo.frameRate)
// 점(.)이 많아질수록 타고타고 들어가는 것이다.

 

 

 

subscript는 안나옴

 

class만 상속 가능 !중요 포인트!

 


 

class Human {
    var age : Int = 1
}
var kim = Human()
var lee = kim //참조 타입
print(kim.age, lee.age)
lee.age = 20
print(kim.age, lee.age)
kim.age = 30
print(kim.age, lee.age)

 

1. 클래스 정의

class Human {
    var age : Int = 1
}
  • Human은 클래스
  • age 프로퍼티 기본값은 1

2. 인스턴스 생성

var kim = Human()
  • Human 객체 하나 생성됨
  • 메모리 어딘가에 객체가 만들어지고
  • kim은 그 객체를 “가리키는 참조”를 가지고 있음

현재 상태:

kim ──> Human(age: 1)

3. 참조 복사

var lee = kim

여기서 중요한 포인트:

  • 값이 복사된 게 아니라
  • 참조(주소)가 복사됨

즉, 같은 객체를 가리킴

현재 상태:

kim ─┐
     ├──> Human(age: 1)
lee ─┘

4. 첫 번째 출력

print(kim.age, lee.age)

결과:

1 1

이유:

  • 둘 다 같은 객체를 보고 있음

5. lee로 값 변경

lee.age = 20
  • lee가 가리키는 객체의 age를 바꿈
  • 그런데 그 객체는 kim도 같이 보고 있음

현재 상태:

kim ─┐
     ├──> Human(age: 20)
lee ─┘

6. 두 번째 출력

print(kim.age, lee.age)

결과:

20 20

이유:

  • 같은 객체를 공유하고 있기 때문

7. kim으로 값 변경

kim.age = 30
  • 역시 같은 객체 수정

현재 상태:

kim ─┐
     ├──> Human(age: 30)
lee ─┘

8. 세 번째 출력

print(kim.age, lee.age)

결과:

30 30

핵심 개념

class는 참조 타입

var lee = kim

이건

  • “복사”가 아니라
  • “같은 객체를 같이 사용”

struct였다면?

만약 struct였다면:

var lee = kim

→ 값이 복사됨

그래서 한쪽 바꿔도 다른 쪽 영향 없음


한 줄 정리

이 코드는
class는 값을 복사하는 게 아니라, 같은 객체를 참조하기 때문에 한쪽을 바꾸면 다른 쪽도 같이 바뀐다는 걸 보여주는 예제다.

 

 

 

 

 


 

 

 

struct Resolution {
    var width = 0
    var height = 0
}
class VideoMode {
    var resolution = Resolution()
    var frameRate = 0
    var name: String?
}
var hd = Resolution(width: 1920, height: 1080)
//자동 Memberwise Initializer
var highDef = hd
//구조체는 값타입(value type)
print(hd.width, highDef.width)
hd.width = 1024
print(hd.width, highDef.width)
var xMonitor = VideoMode()
xMonitor.resolution = hd
xMonitor.name = "LG"
xMonitor.frameRate = 30
print(xMonitor.frameRate)
var yMonitor = xMonitor
//클래스는 참조타입(reference type)
yMonitor.frameRate = 25
print(yMonitor.frameRate)
print(xMonitor.frameRate)

 

 

이 코드는 struct(값 타입) class(참조 타입)의 차이를 한 번에 보여주는 예제이다.
앞부분과 뒷부분이 서로 다른 개념을 설명하고 있으니 나눠서 보자.


1. struct 부분 (값 타입)

struct Resolution {
    var width = 0
    var height = 0
}

구조체 정의. width, height를 가지는 단순 데이터 타입.


1-1. 값 복사

var hd = Resolution(width: 1920, height: 1080)
var highDef = hd

여기서 중요한 점:

  • highDef = hd 는 값 복사
  • 완전히 별개의 객체가 만들어짐

현재 상태:

hd        -> (1920, 1080)
highDef   -> (1920, 1080)  // 복사본

1-2. 출력

print(hd.width, highDef.width)

결과:

1920 1920

1-3. 값 변경

hd.width = 1024

이제 상태는:

hd        -> (1024, 1080)
highDef   -> (1920, 1080)

1-4. 다시 출력

print(hd.width, highDef.width)

결과:

1024 1920

핵심:

  • struct는 복사되기 때문에 서로 영향 없음

2. class 부분 (참조 타입)

class VideoMode {
    var resolution = Resolution()
    var frameRate = 0
    var name: String?
}
  • resolution은 struct
  • VideoMode 자체는 class

2-1. 객체 생성

var xMonitor = VideoMode()
  • VideoMode 객체 하나 생성됨

2-2. 값 설정

xMonitor.resolution = hd
xMonitor.name = "LG"
xMonitor.frameRate = 30

여기서 주의:

  • resolution = hd → struct이므로 값 복사됨

2-3. 출력

print(xMonitor.frameRate)

결과:

30

2-4. 참조 복사

var yMonitor = xMonitor

여기 핵심:

  • class이므로 참조 복사
  • 같은 객체를 가리킴

상태:

xMonitor ─┐
          ├──> VideoMode 객체
yMonitor ─┘

2-5. 값 변경

yMonitor.frameRate = 25
  • 같은 객체를 수정

2-6. 출력

print(yMonitor.frameRate)   // 25
print(xMonitor.frameRate)   // 25

결과:

25
25

이유:

  • 둘 다 같은 객체를 보고 있음

핵심 비교

struct (Resolution)

  • 값 타입
  • 대입 시 복사됨
  • 서로 영향 없음
hd -> 복사 -> highDef

class (VideoMode)

  • 참조 타입
  • 대입 시 주소 공유
  • 서로 영향 있음
xMonitor ─┐
          ├── 같은 객체
yMonitor ─┘

추가로 중요한 포인트 하나

xMonitor.resolution = hd
  • resolution은 struct이기 때문에
  • 여기서는 값 복사 발생

즉,

  • class 안에 struct가 들어있어도
  • struct는 여전히 값 타입으로 동작

한 줄 정리

이 코드는
struct는 복사되는 값 타입이라 독립적으로 동작하고, class는 같은 객체를 공유하는 참조 타입이라 한쪽 변경이 다른 쪽에도 영향을 준다는 것을 보여준다.

 

 

 


 

 

 

 

 

 


핵심 기준 (가장 중요한 한 줄)

“복사되어도 되는 데이터인가?” → struct
“하나의 상태를 여러 곳에서 공유해야 하는가?” → class


1. struct를 써야 하는 경우 (값 타입)

✔ 특징

  • 값이 복사됨
  • 서로 영향 없음
  • 안전함 (side effect 없음)

✔ 이런 상황에서 사용

1) 단순 데이터 묶음

struct Resolution {
    var width: Int
    var height: Int
}
  • 좌표, 크기, 색상 같은 것

2) 독립적인 값이어야 할 때

var a = Resolution(width: 100, height: 100)
var b = a
b.width = 200
  • a는 영향을 받으면 안 되는 경우

3) 불변성이 중요한 경우

let user = User(name: "kim")
  • 값이 바뀌면 안 되는 데이터

4) 계산 중심 데이터

  • 좌표, 수학 값, 설정값

✔ Swift 공식 스타일

Swift는 기본적으로

2. class를 써야 하는 경우 (참조 타입)

✔ 특징

  • 하나의 객체를 여러 곳에서 공유
  • 상태가 계속 변함

✔ 이런 상황에서 사용

1) 여러 곳에서 같은 객체를 써야 할 때

var a = Human()
var b = a
  • a, b가 같은 사람을 가리켜야 함

2) 상태를 공유해야 하는 경우

  • 로그인 사용자
  • 앱 상태
  • 네트워크 매니저

3) 상속이 필요한 경우

class Animal {}
class Dog: Animal {}
  • struct는 상속이 안 됨

4) identity(정체성)가 중요한 경우

예:

  • “이 사람은 같은 사람인가?”
  • “이 객체는 동일한 객체인가?”
if a === b { }  // 같은 객체인지 비교

3. 비교 정리

기준structclass

타입 값 타입 참조 타입
복사 O X (참조 공유)
상속 X O
용도 데이터 객체/상태
안정성 높음 상대적으로 낮음

4. 실무에서 많이 쓰는 기준

struct 쓰는 경우

  • DTO (데이터 전달 객체)
  • 모델 데이터
  • 좌표, 크기, 값
  • API 응답 데이터

class 쓰는 경우

  • ViewController
  • Manager (NetworkManager 등)
  • 상태 공유 객체
  • 싱글톤

5. 중요한 직관

struct

→ “이건 그냥 값이다”

class

→ “이건 하나의 존재다”


6. 한 줄 정리

struct는 “복사되는 데이터”,
class는 “공유되는 객체”라고 생각하면 된다.


 

 

 


 

 

 

 

프로그래밍 언어에서 value 타입과 reference 타입의 차이

1. 가장 중요한 차이 (한 줄)

Value 타입 = 값을 복사해서 사용
Reference 타입 = 같은 객체를 공유해서 사용


2. 메모리 관점에서 차이

2-1. Value 타입

var a = 10
var b = a
b = 20

동작:

  • a의 값이 b로 복사됨
  • 서로 완전히 독립

상태:

a = 10
b = 20

2-2. Reference 타입

class Person {
    var age = 10
}

var a = Person()
var b = a
b.age = 20

동작:

  • a와 b는 같은 객체를 가리킴
  • 값이 아니라 주소(참조)를 공유

상태:

a ─┐
   ├──> Person(age: 20)
b ─┘

3. 핵심 차이 정리

구분Value 타입Reference 타입

저장 값 자체 주소(참조)
복사 값 복사 참조 복사
영향 서로 영향 없음 서로 영향 있음
struct, Int, String class

4. 코드로 비교

Value 타입 (struct)

struct User {
    var age: Int
}

var u1 = User(age: 10)
var u2 = u1

u2.age = 20

print(u1.age) // 10
print(u2.age) // 20

→ 서로 영향 없음


Reference 타입 (class)

class User {
    var age: Int = 10
}

var u1 = User()
var u2 = u1

u2.age = 20

print(u1.age) // 20
print(u2.age) // 20

→ 같은 객체라서 같이 바뀜


5. 왜 중요한가

이 차이 때문에:

Value 타입

  • 안전함
  • 버그 적음
  • 예측 가능

Reference 타입

  • 공유 가능
  • 상태 관리 가능
  • 대신 사이드 이펙트 발생 가능

6. 직관적으로 이해하는 방법

Value 타입

→ “복사해서 쓰는 종이”

Reference 타입

→ “같은 구글 문서 링크 공유”

  • Value: 각자 따로 수정
  • Reference: 한 명 수정하면 다 바뀜

7. Swift 기준 예

  • Value 타입: struct, enum, Int, String, Array
  • Reference 타입: class

8. 한 줄 정리

Value 타입은 데이터를 복사해서 사용하고,
Reference 타입은 하나의 데이터를 여러 곳에서 공유한다.

 

관련글 더보기