dev._.note

[Swift] Class와 Struct, Enum 본문

Dev/SWIFT

[Swift] Class와 Struct, Enum

Laena 2023. 11. 30. 16:08

📌 Class

1. 클래스는 프로퍼티(Property)와 메서드(Method)로 구성. 

✓ 프로퍼티(Properties):

  • 프로퍼티는 클래스, 구조체, 또는 열거형 안에 있는 변수 또는 상수를 나타냄.
  • 클래스의 속성으로 객체의 상태를 저장하거나 제공. 이러한 상태는 클래스의 인스턴스가 가질 수 있는 고유한 데이터를 나타냄.
  • 프로퍼티는 저장 프로퍼티(Stored Properties)와 계산 프로퍼티(Computed Properties)로 나뉨.
  • 저장 프로퍼티: 값을 저장하고, 인스턴스의 일부로서 그 값을 유지.
  • 계산 프로퍼티: 특정한 계산을 통해 값을 반환하며, 값을 저장하지 않고 필요할 때마다 새로 계산.

✓ 메서드(Methods):

  • 메서드는 클래스, 구조체, 또는 열거형 안에 있는 함수를 나타냄.
  • 클래스의 동작을 정의하고, 클래스의 인스턴스에 대해 수행되는 특정한 작업을 수행.
  • 메서드는 인스턴스 메서드(Instance Methods)와 타입 메서드(Type Methods)로 구분.
  • 인스턴스 메서드: 특정 인스턴스에 속하는 동작을 정의하고, 인스턴스의 상태에 접근가능.
  • 타입 메서드: 클래스 자체와 관련된 동작을 정의하며, 특정 인스턴스에 속하는 것이 아닌 클래스 자체에 영향을 줌.

 

2. 클래스는 이니셜라이저(Initializer)를 통해 초기값을 설정가능.

  • 프로퍼티에 기본 값이 없는 경우 이니셜라이저를 필수로 구현해야 하며 그렇지 않을 경우 에러가 발생.

3. 참조 타입

  • 참조 타입은 변수나 상수에 할당될 때에는 값을 복사하는 것이 아니라 참조(주소)가 복사되어 같은 인스턴스를 가리킴. 클래스(Class)가 참조 타입의 대표적인 예시.
  • 참조 타입의 경우 변수나 상수에 할당될 때 참조가 복사되므로, 동일한 인스턴스를 공유함. 따라서 한쪽에서 값을 변경하면 다른 쪽에서도 영향을 받음.
// 참조 타입인 클래스 예시
class Person {
    var name: String

    init(name: String) {
        self.name = name
    }
}

var person1 = Person(name: "Alice")
var person2 = person1 // 참조 복사
person2.name = "Bob"

print(person1.name) // 출력: Bob
print(person2.name) // 출력: Bob
// 예시 1
class Name {
    var name: String

	init(name: String) {
		self.name = name
	}
    
    func sayMyName() {
        print("my name is \(name)")
    }
}

let song : Name = Name(name: "song")

print(song.name) // song
song.sayMyName() // my name is song

song.name = "kim"
song.sayMyName() // my name is kim


// 예시 2
class Person {
    var name: String // 저장 프로퍼티
    
    var introduction: String { // 계산 프로퍼티
        return "제 이름은 \(name)입니다."
    }
    
    init(name: String) {
        self.name = name
    }
}

// Person 객체 생성
let person1 = Person(name: "Alice")
print(person1.introduction) // 출력: 제 이름은 Alice입니다.


// 예시 3
class Counter {
    var count = 0 // 저장 프로퍼티
    
    func increment() { // 인스턴스 메서드
        count += 1
    }
    
    static func reset() { // 타입 메서드
        print("카운터를 초기화합니다.")
    }
}

// Counter 객체 생성
let counter1 = Counter()
counter1.increment()
counter1.increment()
print(counter1.count) // 출력: 2

Counter.reset() // 출력: 카운터를 초기화합니다.

📌 struct(구조체)

  • 구조체는 프로퍼티에 값을 저장하거나 메서드를 통해 기능을 제공하고 이걸 하나로 캡슐화할 수 있는 사용자 정의 타입.
  • 생성자(initializer)를 정의하지 않으면 구조체가 자동으로 생성자(Memberwise Initializer)를 제공.
  • 값 타입
    • 값 타입은 변수나 상수에 할당될 때 값의 복사본이 생성되는 타입. 주로 구조체(Structures), 열거형(Enumerations), 기본 데이터 타입(Int, Double, Bool, 등)이 값 타입에 해당.
// 값 타입인 구조체 예시
struct Point {
    var x: Int
    var y: Int
}

var point1 = Point(x: 5, y: 10)
var point2 = point1 // 값 복사
point2.x = 15

print(point1) // 출력: Point(x: 5, y: 10)
print(point2) // 출력: Point(x: 15, y: 10)
  • 클래스와 달리 구조체는 상속 불가능.
  • 클래스와 같이 인스턴스로 만들어 사용할 수 있음.
struct Coffee {
  var name: String?
  var size: String?

  func brewCoffee() -> String {
    if let name = self.name {
      return "\(name) ☕️ 한 잔 나왔습니다"
    } else {
      return "오늘의 커피 ☕️ 한잔 나왔습니다"
    }
  }
}

let americano = Coffee(name: "아메리카노")
// 출력값: 아메리카노 ☕️ 한 잔 나왔습니다

// 따로 init()을 구현하지 않아도 자동으로 생성자를 받습니다.

// Memberwise Initializer 예시
struct ShoppingListItem {
    let name: String?
    let quantity: Int
    var purchased = false
}

let item1 = ShoppingListItem(name: "칫솔", quantity: 1)
let item2 = ShoppingListItem(name: "치약", quantity: 1, purchased: true)
let item3 = ShoppingListItem(name: nil, quantity: 1, purchased: true)

📌 Enum(열거형)

  • Enum은 관련된 값으로 이뤄진 그룹을 같은 타입으로 선언해 타입 안전성(type-safety)을 보장하는 방법으로 코드를 다룰 수 있음.
  • 값 타입
// 간단한 열거형 선언
enum CompassDirection {
    case north
    case south
    case east
    case west
}

// 열거형의 인스턴스 생성 및 사용
var direction = CompassDirection.north
var anotherDirection = direction // 값 복사

direction = .east // 값을 변경해도 anotherDirection에는 영향이 없음

print(direction) // 출력: east
print(anotherDirection) // 출력: north
  • Swift의 열거형(Enum)은 연관 값(Associated Values)을 가질 수 있음. 이는 각 case가 특정 값을 연결하여 저장할 수 있는 기능을 제공.
// 연관 값을 가진 열거형 선언
enum Trade {
    case buy(stock: String, amount: Int)
    case sell(stock: String, amount: Int)
    case hold
}

// 열거형의 인스턴스 생성 및 사용
let trade1 = Trade.buy(stock: "AAPL", amount: 100)
let trade2 = Trade.sell(stock: "GOOG", amount: 50)
let trade3 = Trade.hold

// switch 문을 사용하여 연관 값 추출
func processTrade(trade: Trade) {
    switch trade {
    case .buy(let stock, let amount):
        print("Buy \(amount) shares of \(stock).")
    case .sell(let stock, let amount):
        print("Sell \(amount) shares of \(stock).")
    case .hold:
        print("Hold this position.")
    }
}

// 각 열거형 케이스에 따라 다른 동작 수행
processTrade(trade: trade1) // 출력: Buy 100 shares of AAPL.
processTrade(trade: trade2) // 출력: Sell 50 shares of GOOG.
processTrade(trade: trade3) // 출력: Hold this position.
enum CompassPoint {
    case north
    case south
    case east
    case west
}

// 한 케이스 선언 방법
var directionToHead = CompassPoint.west
directionToHead = .east

// 활용 예시 1
directionToHead = .south
switch directionToHead {
case .north:
    print("북쪽")
case .south:
    print("남쪽")
case .east:
    print("동쪽")
case .west:
    print("서쪽")
}
// 출력값: "남쪽"

// allCases 
enum Beverage: CaseIterable {
    case coffee, tea, juice
}
let numberOfChoices = Beverage.allCases.count
print("\(numberOfChoices) 잔 주문 가능합니다.")
// 출력값: 3잔 주문 가능합니다
// 실제 Optional의 정의
@frozen public enum Optional<Wrapped> : ExpressibleByNilLiteral {

    /// The absence of a value.
    ///
    /// In code, the absence of a value is typically written using the `nil`
    /// literal rather than the explicit `.none` enumeration case.
    case none

    /// The presence of a value, stored as `Wrapped`.
    case some(Wrapped)


print(Optional.none == nil) // true

 

참고 자료: The Swift Programming Language - Enumerations

 

💡Class, Struck, Enum의 차이점

  • 붕어빵 만드는 기계를 클래스(class), 붕어빵을 그 기계로 만들어진 실제 객체(object)로 비유할 수 있음.
  • 객체는 클래스를 실체화한 것, 프로그래밍에서는 메모리에 올라가는 인스턴스가 된 것.
  • 객체는 클래스의 인스턴스로 자신만의 속성(프로퍼티)과 행위(메서드)를 가짐.
class Car {
  let model: String   
  let price: Int 

  init(modelName: String, price: Int) {
     self.model = modelName
     self.price = price
  }

  func drive() {
		// 구현 코드
  }
}

// Car 클래스를 인스턴스화 시킨 것
var momCar = Car(modelName: "Kia", price: 1000)
momCar.drive()
  • 클래스와 구조체(Struck), 열거형(Enum) 모두 메모리에 할당되고 그 생성된 대상을 인스턴스(instance)라고 합니다. 스위프트에서는 클래스의 인스턴스(instance)를 특별히 객체(object)라고 함.
  • 메모리 저장 방식
    • 구조체, 열거형
      1. 값 타입(Value Type)
      2. 인스턴스 데이터를 모두 스택(Stack)에 저장
      3. 새로운 변수에 할당(값을 전달할 때마다)할 때마다 복사본을 생성 (다른 메모리 공간 생성)
      4. 스택(Stack)의 공간에 저장, 스택 프레임 종료 시, 메모리에서 자동 제거
    • 클래스
      1. 참조 타입(Reference Type)
      2. ARC시스템을 통해 메모리 관리
      3. 인스턴스 데이터는 힙(Heap)에 저장, 해당 힙을 가리키는 변수는 스택에 저장하고 변수의 메모리 주소값이 힙을 가리킴
      4. 값을 전달하는 것이 아니고, 저장된 주소를 전달
struct MyInfoStruct {
	let name: String
	let height: Int
}

let info = MyInfoStruct(name: "peter", height: 180)
let infoCopy = info
info.name = "jane"
print(info.name) // jane
print(infoCopy.name) // peter 


class MyInfoClass {
	let name: String
	let height: Int

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

let info2 = MyInfoClass(name: "peter", height: 180)
let infoCopy2 = info2
info2.name = "jane"
print(info2.name) // jane
print(infoCopy2.name) // jane

'Dev > SWIFT' 카테고리의 다른 글

[Swift] 초기화(Initialization)  (1) 2023.11.30
[Swift] 상속(Inheritance)  (0) 2023.11.30
[Swift] radix  (0) 2023.11.29
[Swift] 객체지향(OOP/Object-Oriented-Programming)  (0) 2023.11.29
[Swift] Array와 Set, Dictionary  (1) 2023.11.29