iOS 실무 7주차 enum struct 구조체와 클래스

2025. 4. 17. 14:06iOS앱개발

안녕하세요! enum (열거형)은 많은 프로그래밍 언어에서 지원하는 기능입니다. enum은 관련된 상수 값들의 집합에 이름을 부여하여 코드의 가독성과 유지보수성을 높이는 데 사용됩니다.

enum을 지원하는 주요 프로그래밍 언어는 다음과 같습니다:

  1. C/C++: C 언어에서 시작되어 C++에서도 강력하게 지원됩니다. C++11부터는 enum class라는 타입 안전성이 강화된 형태도 제공합니다.
  2. Java: enum 키워드를 사용하여 클래스처럼 정의하며, 단순한 상수 집합 이상의 기능 (메소드, 생성자 포함 가능)을 제공합니다.
  3. C#: enum 키워드를 사용하며, 정수형 기반의 명명된 상수 집합을 정의합니다.
  4. Swift: 강력한 타입 추론과 함께 enum을 지원하며, 연관 값(associated values)이나 원시 값(raw values)을 가질 수 있고 메소드도 정의할 수 있어 매우 유연합니다.
  5. Kotlin: Java와 유사하게 enum class 키워드를 사용하며, 프로퍼티와 메소드를 가질 수 있습니다.
  6. Python: enum 모듈을 통해 Enum 클래스를 상속받아 열거형을 정의할 수 있습니다. (Python 3.4 버전부터 표준 라이브러리에 포함)
  7. Rust: enum 키워드를 사용하며, Swift처럼 연관 데이터를 가질 수 있어 강력한 데이터 모델링 도구로 사용됩니다. 패턴 매칭과 함께 자주 사용됩니다.
  8. TypeScript: JavaScript의 상위 집합으로, 숫자형 또는 문자열 기반의 enum을 지원합니다.
  9.  
enum Compass {
    case East
    case North
    case South
    case West
}
var direction: Compass
direction = .South
switch direction { //switch의 비교값이 열거형 Compass
case .East:
    print("동")
case .North: //direction이 .North이면 "북" 출력
    print("북")
case .South:
    print("남")
case .West:
    print("서") //모든 열거형 case를 포함하면 default 없어도 됨
}
enum Week {
    case Fri, Mon, Sat, Sun, Thur, Tue, Wed

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

위와같이 열거형에는 메서드도 넣을 수 있다.

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

enum에 rawValue에 접근하려면 자료형을 지정해주고 .rawValue로 접근할 수 있다.

 

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일") // 주석 처리하면 intDate 케이스가 실행됨

switch todayDate {
case .intDate(let year, let month, let day):
    print("\(year)년 \(month)월 \(day)일")
case .stringDate(let date):
    print(date)
}

연관 값(Associated Value)을 갖는 Enum

Swift의 열거형(Enum)은 단순히 이름이 있는 값들의 모음일 뿐만 아니라, 각 케이스와 관련된 추가적인 정보를 저장할 수 있는 강력한 기능을 제공합니다. 이를 연관 값(Associated Value)이라고 합니다.

 

기본적인 Enum과의 차이점:

일반적인 열거형의 각 케이스는 그 자체로 하나의 독립적인 값입니다. 예를 들어, 이전 예시의 Compass 열거형에서 .North, .South, .East, .West는 각각 고유한 의미를 가지는 상수 값입니다.

반면, 연관 값을 갖는 열거형의 각 케이스는 특정 타입의 값을 "연결"하거나 "포함"할 수 있습니다. 이를 통해 각 케이스에 대한 더 자세한 정보를 함께 저장하고 전달할 수 있습니다.

 

 

옵셔널도 enum 타입으로 만들어졌기 때문에 아래와 같이 사용 가능하다.

var x : Int? = 20 //.some(20)
var y : Int? = Optional.some(10)
var z : Int? = Optional.none
var x1 : Optional<Int> = 30
print(x, y, z, x1) //Optional(20) Optional(10) nil Optional(30)

 

enum DownloadStatus {
    case waiting
    case downloading(progress: Double) // 다운로드 진행률
    case finished(fileURL: URL)       // 완료된 파일 URL
    case error(message: String)        // 오류 메시지
}

var currentStatus = DownloadStatus.downloading(progress: 0.75)

switch currentStatus {
case .downloading(let progress):
    print("다운로드 진행 중: \(progress * 100)%")
case .finished(let url):
    print("다운로드 완료. 파일 위치: \(url)")
case .error(let msg):
    print("오류 발생: \(msg)")
default:
    print("대기 중")
}

 

 

구조체

struct Resolution { //구조체 정의
var width = 1024 //프로퍼티
var height = 768
}

let myComputer = Resolution() //인스턴스 생성
print(myComputer.width) //프로퍼티 접근
class Resolution { 
    var width = 1024 
    var height = 768
}

let myComputer = Resolution(width: 1000, height: 2000)//에러
print(myComputer.width) //프로퍼티 접근
struct Resolution { 
    var width = 1024 
    var height = 768
}

let myComputer = Resolution(width: 1000, height: 2000)// 구조체는 에러 x
print(myComputer.width) //프로퍼티 접근

클래스의 경우에는

class Resolution { 
    var width = 1024 
    var height = 768
    init (width: Int, height: Int) {
        self.width = width
        self.height = height
    }
}

let myComputer = Resolution(width: 1000, height: 2000)
print(myComputer.width) //프로퍼티 접근

이런 방식으로 직접 생성자를 만들어주어야 오류가 나지 않지만 구조체의 경우에는 width, height를 받는 생성자를 만들어주지 않아도 에러가 나지 않는다.

이러한 이유는 구조체의 Memberwise Initializer가 자동으로 생성되기 때문이다.

이와같이 swift의 기본 자료형은 모두 구조체로 이루어져 있다.

선택 기준 요약:

특징구조체 (Struct)클래스 (Class)
타입 값 타입 (Value Type) 참조 타입 (Reference Type)
할당 및 전달 복사 참조 (메모리 주소)
상속 불가능 가능
식별성 독립적인 값 동일한 객체 참조 가능
생명 주기 관리 스코프 기반 자동 관리 참조 카운팅 (ARC)
불변성 let으로 선언 시 속성 불변 인스턴스 자체는 변경 가능
기본 생성자 멤버와이즈 생성자 자동 제공 (조건부) 사용자 정의 필요 (또는 기본 값 제공)
사용 경우 단순 데이터, 값 의미 강조, 불변성, 상속 불필요 객체 식별성, 상속 필요, 공유 가능한 가변 상태

일반적인 Swift 코딩 스타일:

  • 기본적으로 구조체를 사용: 단순한 데이터 모델이나 값 타입의 의미가 중요한 경우에는 구조체를 먼저 고려합니다.
  • 상속 또는 객체 식별성이 필요할 때 클래스 사용: 계층적인 구조를 만들거나 여러 곳에서 동일한 객체를 공유하고 변경해야 하는 경우에는 클래스를 사용합니다.
  • Foundation 프레임워크와의 호환성: NSString, NSArray, NSDictionary 등 Objective-C 기반의 Foundation 프레임워크 클래스와의 상호 운용이 필요한 경우 클래스를 사용해야 할 수 있습니다.

 

클래스 내에 구조체

struct Resolution {
    var width = 1024
    var height = 768
}
class VideoMode {
    var resolution = Resolution()
    var frameRate = 0.0
}

let myVideo = VideoMode()
print(myVideo.resolution.width)

 

class vs struct

저장 위치 스택(Stack) 힙(Heap)
데이터 저장 방식 실제 데이터 값 저장 데이터의 메모리 주소(참조) 저장
복사 시 동작 데이터의 복사본 생성 동일한 객체를 참조
독립성 변수 간 독립적 변수 간 상호 영향 가능
사용 예시 기본형 데이터 (int, bool 등) 객체, 배열, 문자열 등

Class

class Human {
    var age : Int = 1
}
var kim = Human()
var lee = kim //값 타입

print(kim.age, lee.age) // 1 1
lee.age = 20
print(kim.age, lee.age) // 20 20
kim.age = 30
print(kim.age, lee.age) // 30 30

참조 타입 (Reference Type)

  • 특징:
    • 변수에 할당되거나 함수에 전달될 때 **데이터의 메모리 주소 (참조)**가 전달됩니다.
    • 여러 변수가 동일한 메모리 공간을 참조합니다.
    • 하나의 참조 변수를 통해 데이터를 변경하면 다른 모든 참조 변수에도 그 변경 사항이 반영됩니다.

struct

struct Human {
    var age : Int = 1
}
var kim = Human()
var lee = kim //값 타입

print(kim.age, lee.age) // 1 1
lee.age = 20
print(kim.age, lee.age) // 1 20
kim.age = 30
print(kim.age, lee.age) // 30 20

 

값 타입 (Value Type)

  • 특징:
    • 변수에 할당되거나 함수에 전달될 때 값이 복사되어 전달됩니다.
    • 각 인스턴스는 자신만의 독립적인 데이터 복사본을 가집니다.
    • 한 값 타입 변수의 값을 변경해도 다른 값 타입 변수에는 영향을 주지 않습니다.

 

class 참조 타입 O 복잡한 객체, 상태 공유 ARC, deinit
struct 값 타입 X 간단한 데이터 모델 복사 기반
enum 값 타입 X 선택지 제한, 상태 관리 연관값, switch 필수
protocol 해당 없음 X 공통 인터페이스, 추상화 다형성 지원
extension 해당 없음 X 기능 확장, 코드 분리 저장 속성 추가 불가
import Foundation

// 1. protocol: 모든 도형이 따라야 하는 공통 인터페이스
protocol Shape {
    var position: Point { get set }
    func draw()
}

// 2. struct: 값 타입으로 위치(Point) 표현
struct Point {
    var x: Double
    var y: Double
}

// 3. enum: 다양한 도형 종류
enum ShapeType {
    case circle(radius: Double)
    case rectangle(width: Double, height: Double)
}

// 4. class: 도형을 담고 그리는 뷰 (참조 타입)
class ShapeView {
    private var shapes: [Shape] = []

    func addShape(_ shape: Shape) {
        shapes.append(shape)
    }

    func drawAll() {
        for shape in shapes {
            shape.draw()
        }
    }
}

// 5. struct: 도형 구현 (Circle, Rectangle)
struct Circle: Shape {
    var position: Point
    var radius: Double

    func draw() {
        print("🔵 Circle at (\(position.x), \(position.y)) with radius \(radius)")
    }
}

struct Rectangle: Shape {
    var position: Point
    var width: Double
    var height: Double

    func draw() {
        print("🟥 Rectangle at (\(position.x), \(position.y)) size \(width)x\(height)")
    }
}

// 6. extension: protocol 기본 구현 확장
extension Shape {
    func moveBy(x dx: Double, y dy: Double) -> Self {
        var copy = self
        copy.position = Point(x: position.x + dx, y: position.y + dy)
        return copy
    }
}

// ✅ 테스트 코드
let circle = Circle(position: Point(x: 10, y: 20), radius: 5)
let rect = Rectangle(position: Point(x: 0, y: 0), width: 10, height: 20)

let view = ShapeView()
view.addShape(circle)
view.addShape(rect)

view.drawAll()

'iOS앱개발' 카테고리의 다른 글

iOS실무 10주차  (0) 2025.05.08
iOS실무 9주차 Restful  (0) 2025.05.02
iOS실무 6주차  (0) 2025.04.10
iOS실무 5주차- 맛집 앱 개발(1) Table View  (0) 2025.04.03
iOS 실무 4주차  (0) 2025.03.27