[Swift] struct, class, enum

최승원·2022년 5월 10일
0

TIL (Today I Learned)

목록 보기
13/21

인스턴스 멤버 vs 타입 멤버

간단하게는 앞에 static이 붙지 않으면 인스턴스 멤버, 붙으면 타입 멤버이다.

struct Sample {
	// 인스턴스 프로퍼티
    var mutableProperty: Int = 100
    let immutableProperty: Int = 100
    
    // 타입 프로퍼티
    static var typeProperty: Int = 100
    
    // 인스턴스 메서드
    func instanceMethod() {
        print("instance method")
    }
    
    // 타입 메서드
    static func typeMethod() {
        print("type method")
    }
}

인스턴스 멤버(프로퍼티 & 메서드)는 말 그대로 인스턴스를 생성해야 사용이 가능하다.
반면, 타입 멤버는 인스턴스 없이 타입 이름만 알면 접근 가능하다.

// 인스턴스 프로퍼티
var mutable: Sample = Sample()
mutable.mutableProperty = 200

// 타입 메서드와 프로퍼티
Sample.typeProperty = 300
Sample.typeMethod()

타입 메서드에서 인스턴스 멤버는 사용할 수 없다. 왜냐하면 인스턴스 멤버는 인스턴스를 선언해야만 저장 공간을 갖기 때문이다.

class Eve {
    let name = "eve"               
    static let alias = "colli"  
 
    static func sayHello() {
        print(name) // error! Instance member 'name' cannot be used on type 'Eve'
        print(alias)
    }
}

하지만 인스턴스 메서드에서는 인스턴스 멤버와 타입 멤버 모두에 접근이 가능하다.

class Eve {
    let name = "eve"               
    static let alias = "colli"  
 
    func sayHello() {
        print(name)
        print(Eve.alias)
    }
}

타입 메서드의 종류

타입 메서드에는 static 메서드와 class 메서드가 있는데 오버라이딩이 가능한지의 여부에 따라 갈린다.

class Sample {
    var mutableProperty: Int = 100
    let immutableProperty: Int = 100
    
    static var typeProperty: Int = 100
    
    // 재정의(오버라이딩) 가능
    static func instanceMethod() {
        print("type method - static")
    }
    
    // 재정의(오버라이딩) 불가능
    class func typeMethod() {
        print("type method - class")
    }
}

class의 가변성

let으로 class의 instance를 선언해도 내부 mutable property의 값을 바꿀 수 있다.

// 위의 코드에 이어서
let immutableReference: Sample = Sample()
immutableReference.mutableProperty = 200

class vs struct

class는 참조 타입, struct는 값 타입이다.
값 타입은 데이터를 전달할 때 값을 복사하여 전달하고, 참조 타입은 데이터를 전달할 때 값의 메모리 위치를 전달한다.

class SimpleClass {
    var count: Int = 0
    deinit { print("할당 해제") } }

struct SimpleStruct {
    var count: Int = 0 }

var class1 = SimpleClass()
var class2 = class1
var class3 = class1

class3.count = 3

print(class1.count) // class3의 값을 변경했지만 참조타입이므로 class1도 변경 되는 것을 볼 수 있습니다.

var struct1 = SimpleStruct()
var struct2 = struct1
var struct3 = struct1

struct2.count = 2
struct3.count = 3

print(struct1.count) // 0
print(struct2.count) // 2 <- 구조체는 값 타입이므로 항상 새로운 메모리가 할당됩니다.
print(struct3.count) // 3

enum(열거형)

enum은 상수 역할의 값들을 보기 좋게 나열한 것이다.

// 원시값(raw value)이 없는 열거형
enum Weekday {
    case mon
    case tue
    case wed
    case thu, fri, sat, sun
}

// raw value가 있는 열거형
// number type
enum Fruit: Int {
    // 가장 먼저 선언된 case부터 0부터 1씩 증가된 값이 들어감
    case apple // 0
    case grape // 1
    case peach // 2
}

enum Fruit2: Int {
    // raw value가 없는 case는 바로 이전 case의 값에 +1
    case apple = 0 // 0
    case grape = 10 // 10
    case peach // 11
}

// Character type - 반드시 raw value가 있어야 함
enum School: Character {
    case elementary = "초"
    case middle = "중"
    case high = "고"
    case university // error
}

// String type
enum School2: String {
    case elementary = "초등"
    case middle = "중등"
    case high = "고등"
    case university // university
}

// rawValue라는 속성을 이용하면 raw value에 접근 가능
print("School2.univeristy.rawValue == \(School2.university.rawValue)")

// raw value를 통해 enum의 case를 return 받을 수 있음
// 이 떄 raw value가 없을 수도 있으므로 반드시 optional 사용
let AppleInstance: Fruit? = Fruit(rawValue: 0) // apple

enum의 연관값

모든 case가 동일한 raw value를 가져야 하고, 그 값은 지정된 한 가지 값이어야 한다는 단점을 보완한 개념이다.

// 열거형 선언 방법
enum AppleProduct {
	case iPad(model: String)
    case iPhone(model: String, storage: Int)
    case macbook(model: String, storage: Int, size: Int)
}

// 열거형 생성 방법
let product: AppleProduct = .iPhone(model: "8", strage: 64)

// switch문 활용법
switch product {
case. iPad("5s"): break // 연관값이 5s면 매칭
case .iPad: break // 연관값 무시
case .iPhone("X", _): break // 연관값 생략도 가능함
case .iPhone(let model, var storage): break // 연관값에 상수 및 변수 바인딩하기
case let .mackbook(model, storage, size): break // 모두 상수(let)인 경우 let을 맨 앞으로 뺄 수 있음

// if 활용법
if case let .iPhone("8", storage) = product { // product의 첫 번째 연관값이 "8"이면 매칭
	print(storage)
}

if case .iPhone(_, 64) = product { // product의 첫 번째 연관값은 상관 없고, 두 번째 연관값이 64면 매칭
	print("iPhone 64GB")
}
profile
문의 사항은 메일로 부탁드립니다🙇‍♀️

0개의 댓글