[Swift] 스위프트 기초 문법 - (4) 구조체, 클래스, 열거형

Yang Si Yeon·2021년 1월 13일
3

Swift

목록 보기
4/6

구조체

스위프트 대부분 타입은 구조체로 이루어져있다. 구조체는 값(value) 타입이며, 타입이름은 대문자 카멜케이스를 사용하여 정의한다.

구조체 문법

구조체를 정의할 때는 struct 키워드를 사용한다.

struct Sample {
    // 가변 프로퍼티
    var mutableProperty: Int = 100
    // 불변 프로퍼티
    let immutableProperty: Int = 100
    // 타입 프로퍼티(static 키워드 사용 : 타입 자체가 사용하는 프로퍼티)
    static var typeProperty: Int = 100
    
    // 인스턴스 메서드(인스턴스가 사용하는 메서드)
    func instanceMethod() {
    	print("instance method")
    }
    // 타입 메서드(static 키워드 사용 : 타입 자체가 사용하는 메서드)
    static func typeMethod() {
   	print("type method")
    }
}

구조체 사용

var mutable: Sample = Sample()
mutable.mutableProperty = 200
mutable.immutableProperty = 200 // 컴파일 오류

let immutable: Sample = Sample()
immutable.mutableProperty = 200 // 컴파일 오류
immutable.immutableProperty = 200 // 컴파일 오류

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

// 인스턴스에서는 타입 프로퍼티나 타입 메서드를 사용할 수 없다.
mutable.typeProperty = 400 // 컴파일 오류
mutable.typeMethod() // 컴파일 오류

구조체 예시

struct Student {
    var name: String = "unknown"
    // 키워드도 `으로 묶어주면 이름으로 사용 가능
    var `class`: String = "Swift"
    
    static func selfIntroduce() {
    	print("학생타입입니다")
    }
    
    func selfIntroduce() {
    	// self는 인스턴스 자신을 지칭, 몇몇 경우를 제외하고 사용은 선택사항
    	print("저는 \(self.class)\(name)입니다")

}

Student.selfIntroduce() // 학생타입입니다

var ssionii: Student = Student()
ssionii.name = "ssionii"
ssionii.class = "스위프트"
ssionii.selfIntroduce() // 저는 스위프트반 ssionii입니다

let jina: Student = Student()

jina.name = "jina" // 컴파일 오류
jina.selfIntroduce() // 저는 Swift반 unknown입니다

클래스

클래스는 참조(reference) 타입이며, 타입이름은 대문자 카멜케이스를 사용하여 정의한다. Swift의 클래스는 다중 상속이 되지 않는다.

클래스 문법

클래스를 정의할 때는 class 키워드를 사용한다.

class 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 - static")
    }
    class func classMethod() {
    	print("type method - class")
    }
}

클래스 사용

클래스의 인스턴스는 참조 타입이므로 let으로 선언되었더라도 인스턴스 프로퍼티의 값 변경이 가능하다.

var mutableReference: Sample = Sample()
mutableReference.mutableProperty = 200
mutableReference.immutableProperty = 200 // 컴파일 오류

let immutableReference: Sample = Sample()
immutableReference.mutableProperty = 200
immutableReference.immutableProperty = 200 // 컴파일 오류

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

// 인스턴스에서는 타입 프로퍼티나 타입 메서드를 사용할 수 없다.
mutableReference.typeProperty = 400 // 컴파일 오류
mutableReference.typeMethod() // 컴파일 오류

클래스 예시

class Student {
    var name: String = "unknown"
    var `class`: String = "Swift"
    
    class func selfIntroduce() {
    	print("학생타입입니다")
    }
    
    func selfIntroduce() {
    	print("저는 \(self.class)\(name)입니다")
    }
}

Student.selfIntroduce() // 학생타입입니다

var ssionii: Student = Student()
ssionii.name = "ssionii"
ssionii.class = "스위프트"
ssionii.selfIntroduce() // 저는 스위프트반 ssionii입니다

let jina: Student = Student()
jina.name = "jina"
jina.selfIntroduce() // 저는 Swift반 jina입니다

열거형

Swift 열거형은 다른 언어의 열거형과 많이 다르다.
Swift 열거형의 특징

  • 유사한 종류의 여러 값을 한 곳에 모아서 정의한 것. 예) 요일, 월, 계절 등
  • enum 자체가 하나의 데이터 타입으로, 대문자 카멜케이스를 사용하여 이름을 정의한다.
  • 각 case는 소문자 카멜케이스로 정의한다.
  • 각 case는 그 자체가 고유의 값이다. (각 case에 자동으로 정수값이 할당되지 x)
  • 각 case는 한 줄에 개별로도, 한 줄에 여러개도 정의할 수 있다.

열거형 문법

enum 이름 {
    case 이름1
    case 이름2
    case 이름3, 이름4, 이름5
    // ...
}

// 예제
enum BoostCamp {
    case iosCamp
    case androidCamp
    case webCamp
}

열거형 사용

타입이 명확할 경우, 열거형의 이름을 생략 할 수 있다. switch 구문에서 사용하면 좋다.

enum Weekday {
    case mon
    case tue
    case wed
    case thu, fri, sat, sun
}

// 열거형 타입과 케이스를 모두 사용하여도 됨
var day: Weekday = Weekday.mon
// 타입이 명확하다면 .케이스 처럼 표현해도 무방
day = .tue

// switch의 비교값에 열거형 타입이 위치할 때
// 모든 열거형 케이스를 포함한다면 default 필요 x
switch day {
case .mon, .tue, .wed, .thu:
	print("평일입니다")
case Weekday.fri:
	print("불금 파티!")
case .sat, .sun:
	print("신나는 주말!")
}

rawValue (원시값)

  • C 언어의 enum 처럼 정수값을 가질 수 있다.
  • rawValue는 case별로 각각 다른 값을 가져야 한다.
  • 자동으로 1이 증가된 값이 할당된다.
  • rawValue를 반드시 지닐 필요가 없다면 굳이 만들지 않아도 된다.
enum Friut: Int {
    case apple = 0
    case grape = 1
    case peach // 2
    // mango와 apple의 원시값이 같으므로 mango 케이스의 원시값을 0으로 정의할 수 없다.
    case mango = 0 
}

정수 타입 뿐만 아니라, Hashable 프로토콜을 따르는 모든 타입을 원시값의 타입으로 지정할 수 있다. 열거형의 원시값 타입이 String일 때, 원시값이 저장되지 않았다면 case의 이름을 원시값으로 사용한다.

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

print("School.middle.rawValue == \(School.middle.rawValue)")
// School.middle.rawValue == 중등

print("School.univerisity.rawValue == \(School.univerisity.rawValue)")
// School.univerisity.rawValue == univerisity

원시값을 통한 초기화

rawValue를 통해 초기화를 할 수 있는데, rawValue가 case에 해당하지 않을 수 있으므로, rawValue를 통해 초기화 한 인스턴스는 옵셔널 타입이다.

let apple: Fruit? = Fruit(rawValue: 0)

// if let 구문을 사용하면 rawValue에 해당하는 케이스를 곧바로 사용 가능
if let orange: Friut = Fruit(rawValue: 5) {
	print("rawValue 5에 해당하는 케이스는 \(orange)입니다")
} else {
	print("rawValue 5에 해당하는 케이스가 없습니다")
} // rawValue 5에 해당하는 케이스가 없습니다

메서드

Swift의 열거형에는 메서드도 추가할 수 있다.

enum Month {
    case dec, jan, feb
    case mar, apr, may
    case jun, jul, aug
    case sep, oct, nov
    
    func printMessage() {
    	switch self {
        case .mar, .apr, .may:
        	print("봄")
        case .jun, .jul, .aug:
        	print("여름")
        case .sep, .oct, .nov:
        	print("가을")
        case .dec, .jan, .feb:
        	print("겨울")
        }
    }
}

클래스 vs 구조체/열거형

클래스는 참조 타입, 구조체와 열거형은 값 타입이라는 것이 가장 큰 차이점이다. 클래스는 상속이 가능하지만 열거형과 구조체는 상속이 불가능하다.

값 타입과 참조 타입 비교

  • 값 타입(value type): 데이터를 전달 할 때 값을 복사하여 전달
  • 참조 타입(reference type): 데이터를 전달 할 때 값의 메모리 위치를 전달
struct ValueType {
    var property = 1
}

class ReferenceType {
    var property = 1
}

let firstStructInstance = ValueType()
var secondStructInstance = firstStructInstance
secondStructInstace.property = 2

print("first struct instace property : \(firstStructInstaceProperty)") // 1
print("second struct instace property : \(secondStructInstaceProperty)") // 2

let firstClassReference = ReferenceType()
let secondClassReference = firstClassReferece
secondClassReference.property = 2

print("first class reference property : \(firstClassReferenceProperty)") // 2
print("second class reference property : \(secondClassReferenceProperty)") // 2

값 타입을 사용하는 경우

  • 연관된 몇몇의 값들을 모아서 하나의 데이터 타입으로 표현하고 싶은 경우
  • 다른 객체 또는 함수 등으로 전달될 때 참조가 아니라 복사(값 복사) 할 경우
  • 자신을 상속할 필요가 없거나, 다른 타입을 상속 받을 필요가 없는 경우

스위프트에서의 사용

  • 스위프트의 기본 데이터 타입은 모두 구조체로 구현되어 있음
  • 스위프트는 구조체와 열거형 사용을 선호함
  • Apple 프레임워크는 대부분 클래스를 사용함
  • 구조체/클래스 선택과 사용은 나의 몫,,


해당 글은 boostcourse의 'iOS 프로그래밍을 위한 스위프트 기초' 강좌를 수강한 후 작성한 글 입니다.

profile
가장 젊은 지금, 내가 성장하는 데에 쓰자

0개의 댓글