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

우리가 흔히 아는 “진짜 enum” 느낌
단순 enum보다 더 강력 (패턴 매칭 가능)
이쪽은 enum이라기보다 “Algebraic Data Type (ADT)” 형태
예전엔 없었는데 요즘 많이 생김
임베디드, 성능 중심
“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>
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
값이 있냐 / 없냐를 안전하게 구분하려고
C나 Java처럼 하면:
Swift는:
두 경우를 강제로 구분하게 만듦
if let value = num {
print(value)
}
이건 사실 내부적으로:
switch num {
case .some(let value):
print(value)
case .none:
break
}
이거랑 똑같은 구조야
👉 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("경로우대입니다")
}
let age: Int? = 30
이건 내부적으로:
Optional.some(30)
즉,
핵심:
위에서부터 순서대로 “조건이 맞는 case 하나만 실행”
case .none:
age는 .some(30)이라서 ❌ (nil 아님)
case .some(let a) where a < 20:
이것도 실패
case .some(let a) where a < 71:
여기서 처음으로 조건이 맞음 → 실행됨
print("30살 성인입니다")
그리고 switch 끝남 (아래 안 내려감)
이미 위에서 매칭됐기 때문에 실행 안 됨
Optional에서 값 꺼내는 것
.some(30) → a = 30
추가 조건 필터
case .some(let a) where a < 20
=
“값이 있고, 그 값이 20 미만이면”
조건 맞는 첫 번째 case에서 끝
.some(30) →
→ .none ❌
→ <20 ❌
→ <71 ✅→ 실행 → 끝
30살 성인입니다
이 코드는 사실 이렇게 생각하면 쉽다:
if age == nil {
...
} else if age < 20 {
...
} else if age < 71 {
...
} else {
...
}
근데 Swift는 Optional이라서
.some, .none으로 나눠서 처리하는 것
실무/학습에서 자주 쓰이는 struct 지원 언어들
“구조체”의 기본 개념
특징
요즘 개발에서 많이 쓰는 형태
특징
특징
struct라는 키워드는 없지만 비슷한 개념 존재
이런 언어들은
struct 대신 class/객체로 통합해서 사용
struct는 크게 2가지 스타일로 나뉨:
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 initializer는
구조체의 모든 프로퍼티를 하나씩 받아서 초기화해주는 기본 생성자
Swift에서는 struct를 만들면, 별도로 생성자를 안 써도 자동으로 만들어준다.
struct Resolution {
var width = 1024
var height = 768
}
이 구조체를 정의하면 Swift가 내부적으로 이런 생성자를 자동으로 만들어준다:
init(width: Int, height: Int) {
self.width = width
self.height = height
}
이게 바로 memberwise initializer 이다.
let yourComputer = Resolution(width: 200, height: 300)
이 부분이 memberwise initializer를 사용한 거다.
을 직접 넣어서 객체를 만든 것
var width = 1024
var height = 768
이렇게 기본값이 있어도, memberwise initializer는 여전히 생성된다.
그래서 두 가지 방식이 다 가능하다:
Resolution() // 기본값 사용
Resolution(width: 200, height: 300) // 직접 지정
struct Resolution {
var width = 1024
var height = 768
init() {
width = 0
height = 0
}
}
이렇게 직접 init을 만들면
기본 memberwise initializer (init(width:height:))는 더 이상 자동 생성되지 않는다.
이름 그대로:
각 프로퍼티를 하나씩 받아서 초기화한다는 의미다.
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)
class Human {
var age : Int = 1
}
var kim = Human()
현재 상태:
kim ──> Human(age: 1)
var lee = kim
여기서 중요한 포인트:
즉, 같은 객체를 가리킴
현재 상태:
kim ─┐
├──> Human(age: 1)
lee ─┘
print(kim.age, lee.age)
결과:
1 1
이유:
lee.age = 20
현재 상태:
kim ─┐
├──> Human(age: 20)
lee ─┘
print(kim.age, lee.age)
결과:
20 20
이유:
kim.age = 30
현재 상태:
kim ─┐
├──> Human(age: 30)
lee ─┘
print(kim.age, lee.age)
결과:
30 30
var lee = kim
이건
만약 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(참조 타입)의 차이를 한 번에 보여주는 예제이다.
앞부분과 뒷부분이 서로 다른 개념을 설명하고 있으니 나눠서 보자.
struct Resolution {
var width = 0
var height = 0
}
구조체 정의. width, height를 가지는 단순 데이터 타입.
var hd = Resolution(width: 1920, height: 1080)
var highDef = hd
여기서 중요한 점:
현재 상태:
hd -> (1920, 1080)
highDef -> (1920, 1080) // 복사본
print(hd.width, highDef.width)
결과:
1920 1920
hd.width = 1024
이제 상태는:
hd -> (1024, 1080)
highDef -> (1920, 1080)
print(hd.width, highDef.width)
결과:
1024 1920
핵심:
class VideoMode {
var resolution = Resolution()
var frameRate = 0
var name: String?
}
var xMonitor = VideoMode()
xMonitor.resolution = hd
xMonitor.name = "LG"
xMonitor.frameRate = 30
여기서 주의:
print(xMonitor.frameRate)
결과:
30
var yMonitor = xMonitor
여기 핵심:
상태:
xMonitor ─┐
├──> VideoMode 객체
yMonitor ─┘
yMonitor.frameRate = 25
print(yMonitor.frameRate) // 25
print(xMonitor.frameRate) // 25
결과:
25
25
이유:
hd -> 복사 -> highDef
xMonitor ─┐
├── 같은 객체
yMonitor ─┘
xMonitor.resolution = hd
즉,
이 코드는
struct는 복사되는 값 타입이라 독립적으로 동작하고, class는 같은 객체를 공유하는 참조 타입이라 한쪽 변경이 다른 쪽에도 영향을 준다는 것을 보여준다.

“복사되어도 되는 데이터인가?” → struct
“하나의 상태를 여러 곳에서 공유해야 하는가?” → class
struct Resolution {
var width: Int
var height: Int
}
var a = Resolution(width: 100, height: 100)
var b = a
b.width = 200
let user = User(name: "kim")
Swift는 기본적으로
var a = Human()
var b = a
class Animal {}
class Dog: Animal {}
예:
if a === b { } // 같은 객체인지 비교
기준structclass
| 타입 | 값 타입 | 참조 타입 |
| 복사 | O | X (참조 공유) |
| 상속 | X | O |
| 용도 | 데이터 | 객체/상태 |
| 안정성 | 높음 | 상대적으로 낮음 |
→ “이건 그냥 값이다”
→ “이건 하나의 존재다”
struct는 “복사되는 데이터”,
class는 “공유되는 객체”라고 생각하면 된다.
Value 타입 = 값을 복사해서 사용
Reference 타입 = 같은 객체를 공유해서 사용
var a = 10
var b = a
b = 20
동작:
상태:
a = 10
b = 20
class Person {
var age = 10
}
var a = Person()
var b = a
b.age = 20
동작:
상태:
a ─┐
├──> Person(age: 20)
b ─┘
구분Value 타입Reference 타입
| 저장 | 값 자체 | 주소(참조) |
| 복사 | 값 복사 | 참조 복사 |
| 영향 | 서로 영향 없음 | 서로 영향 있음 |
| 예 | struct, Int, String | class |
struct User {
var age: Int
}
var u1 = User(age: 10)
var u2 = u1
u2.age = 20
print(u1.age) // 10
print(u2.age) // 20
→ 서로 영향 없음
class User {
var age: Int = 10
}
var u1 = User()
var u2 = u1
u2.age = 20
print(u1.age) // 20
print(u2.age) // 20
→ 같은 객체라서 같이 바뀜
이 차이 때문에:
→ “복사해서 쓰는 종이”
→ “같은 구글 문서 링크 공유”
Value 타입은 데이터를 복사해서 사용하고,
Reference 타입은 하나의 데이터를 여러 곳에서 공유한다.
| iOS프로그래밍_9주차_Open API 기반iOS앱 개발(1)RESTful/JSON/Open API (0) | 2026.05.04 |
|---|---|
| 중간고사 (semi-openbook) 안내 (0) | 2026.04.20 |
| iOS 프로그래밍실무_6주차_옵셔널 체이닝(Optional Chaining) (0) | 2026.04.13 |
| 5주차_iOS프로그래밍_맛집 iOS앱 개발 (0) | 2026.04.06 |
| iOS프로그래밍_4주차_클래스(class) 상속 (0) | 2026.03.30 |