스위프트에서 클래스와 구조체는 많은 공통점이 있다. 클래스와 구조체 둘 다 다음과 같은 기능이 가능하다.
값을 저장하기 위한 프로퍼티 정의 |
기능을 제공하기 위한 메소드 정의 |
subscript 문법을 이용해 특정 값을 접근할 수 있는 subsscript 정의 |
초기 상태를 설정할 수 있는 initializer 정의 |
기본 구현에서 기능 확장 |
특정한 종류의 표준 기능을 제공하기 위한 프로토콜 순응(conform) |
구조체로는 가능하지 않고 클래스만 가능한 기능은 아래와 같다.
상속 (Inheritance) : 클래스의 여러 속성을 다른 클래스에 물려 줌 |
타입 캐스팅 (Type casting) : 런타임에 클래스 인스턴스의 타입을 확인 |
소멸자 (Deinitializers) : 할당된 자원을 해제(free up) 시킴 |
참조 카운트 (Reference counting) : 클래스 인스턴스에 하나 이상의 참조가 가능 |
선언 문법 (Definition Syntax)
class SomeClass{
// 클래스 내용
}
struct SomeStructure {
// 구조체 내용
}
✔️ 위의 예제와 같이 클래스는 class 키워드를, 구조체는 struct 키워드를 이름 앞에 적어서 선언한다.
클래스와 구조체 인스턴스 (Class and Structure Instances)
struct Information {
var height = 0
var name: String = "Seongil"
}
class Korea {
var capital: String = "Seoul"
var randmark: String = "Gyeongbokgung"
var population: Int = 5000
}
let someInformation = Information() // 구조체 인스턴스
let someKorea = Korea() // 클래스 인스턴스
✔️ 위의 예제와 같이 클래스와 구조체 이름 뒤에 빈 괄호를 적으면 각각의 인스턴스를 생성할 수 있다.
프로퍼티 접근 (Accessing Properties)
struct Information {
var height = 0
var name: String = "Seongil"
}
class Korea {
var capital: String = "Seoul"
var randmark: String = "Gyeongbokgung"
var population: Int = 5000
}
let someInformation = Information() // 구조체 인스턴스
let someKorea = Korea() // 클래스 인스턴스
print("capital: \(someKorea.capital)")
// capital: Seoul
✔️ 위의 예제와 같이 점 문법을 통해 클래스 인스턴스와 구조체 인스턴스의 프로퍼티에 접근할 수 있다.
struct Information {
var height = 0
var name: String = "Seongil"
}
class Korea {
var capital: String = "Seoul"
var randmark: String = "Gyeongbokgung"
var population: Int = 5000
}
var someInformation = Information() // 구조체 인스턴스
var someKorea = Korea() // 클래스 인스턴스
someInformation.height = 178
print("height: \(someInformation.height)")
// height: 178
✔️ 위의 예제와 같이 점문법을 이용해 값을 할당할 수 있다.
구조체형의 맴버 초기화 (Memberwise Initializers for Structure Types)
struct Information {
var height = 0
var name: String = "Seongil"
}
var test = Information(height: 178, name: "Yeo")
print("height: \(test.height), name: \(test.name)")
// height: 178, name: Yeo
✔️ 위의 예제와 같이 모든 구조체는 초기화시 프로퍼티를 선언할 수 있는 초기자를 자동으로 생성해 제공한다.
구조체와 열거형은 값 타입 (Structures and Enumerations Are Value Types)
값 타입은 함수에서 상수나 변수에 전달될 때 그 값이 복사되서 전달 된다는 의미이다. 스위프트에서 모든 구조체와 열거형 타입은 값 타입이다.
struct Information {
var height = 0
var name: String = "Seongil"
}
var test = Information(height: 178, name: "Yeo")
var test2 = test
✔️ 위의 예제에서 Information 구조체의 인스턴스 test를 선언한다. 그리고 test를 test2라는 변수에 할당 했다. 그러면 test와 test2는 같을까? 같지 않다. 할당하는 순간 복사되기 때문에 test와 test2는 같지 않고 완전히 다른 인스턴스이다.
struct Information {
var height = 0
var name: String = "Seongil"
}
var test = Information(height: 178, name: "Yeo")
var test2 = test
test2.height = 188
print("test : height=\(test.height), name=\(test.name)")
print("test2 : height=\(test2.height), name=\(test2.name)")
// test : height=178, name=Yeo
// test2 : height=188, name=Yeo
✔️ 위의 예제에서 test2 인스턴스의 height 프로퍼티에 188을 할당하고 출력해보니 test의 height 값은 여전히 원래 값인 178을 가지고 있고, test2의 height 값은 188을 가지고 있는 것을 볼 수 있다. 이는 두 인스턴스가 완전히 다른 개체로 다른 주소 공간에 저장되어 사용된다는 것을 보여준다.
클래스는 참조 타입 (Classes Are Reference Types)
값 타입과 달리 참조 타입은 변수나 상수에 값을 할당 하거나 함수에 인자로 전달할 때 그 값이 복사되지 않고 참조 된다. 참조 된다는 의미는 그 값을 갖고 있는 메모리를 바라보고 있다는 뜻이다.
class Korea {
var capital: String = "Seoul"
var randmark: String = "Gyeongbokgung"
var population: Int = 5000
}
var test = Korea()
test.capital = "Cheongju"
test.population = 10000
test.randmark = "63building"
var test2 = test
test2.capital = "Seoul"
✔️ 위의 예제에서 test라는 Korea 클래스 인스턴스를 생성하고 각 프로퍼티에 값을 할당했다. 그리고 test2라는 변수를 만들고 그것을 위에서 선언한 test 클래스 인스턴스를 할당한다. 그러고 나서 test2의 captial 프로퍼티의 값을 "Seoul"로 변경한다.
class Korea {
var capital: String = "Seoul"
var randmark: String = "Gyeongbokgung"
var population: Int = 5000
}
var test = Korea()
test.capital = "Cheongju"
test.population = 10000
test.randmark = "63building"
print("test capital=\(test.capital), randmark=\(test.randmark), population=\(test.population)")
// test capital=Cheongju, randmark=63building, population=10000
var test2 = test
test2.capital = "Seoul"
print("test capital=\(test.capital), randmark=\(test.randmark), population=\(test.population)")
// test capital=Seoul, randmark=63building, population=10000
print("test2 capital=\(test2.capital), randmark=\(test2.randmark), population=\(test2.population)")
// test2 capital=Seoul, randmark=63building, population=10000
✔️ 위의 예제에서 test 클래스 인스턴스의 capital 프로퍼티의 값을 "cheonju"로 바꾼 후 출력하면 바뀐 값인 "chengju"가 출력 된다. 그리고 test2 클래스 인스턴스의 captial 프로퍼티의 값을 "Seoul"로 바꾼 후 test의 프로퍼티와 test2의 프로퍼티를 출력하면 둘 다 "Seoul"이 출력 된다. test2가 test 인스턴스를 복사한 것이 아니라 참조한 것이기 때문이다. 즉, test가 바라보는 메모리 주소를 test2도 동일하게 바라보고 참조하고 있는 것이다.
식별 연산자 (Identity Operators)
✅ 클래스는 참조 타입이기 때문에 여러 상수와 변수에서 같은 인스턴스를 참조할 수 있다. 상수와 변수가 같은 인스턴스를 참조하고 있는지 비교하기 위해 식별 연산자를 사용한다.
1️⃣ === : 두 상수나 변수가 같은 인스턴스를 참조하고 있는 경우 true
2️⃣ !== : 두 상수나 변수가 다른 인스턴스를 참조하고 있는 경우 true
class Korea {
var capital: String = "Seoul"
var randmark: String = "Gyeongbokgung"
var population: Int = 5000
}
var test = Korea()
var test2 = test
if test === test2 {
print("true")
}
// true
✔️ 위의 예제에서는 test와 test2가 같은 인스턴스를 참조하고 있어서 "true"가 출력된다.
포인터 (Pointers)
✔️ 스위프트에서 상수나 변수가 특정 타입의 인스턴스를 참조하고 있다는 것은 위 포인터와 유사하다. 하지만 C, C++, Objective-C에서 포인터는 실제 메모리를 직접 가르키고 있고 키워드로 표시하지만 스위프트는 참조를 가르키기 위해 사용하지 않고 대신 다른 상수와 변수처럼 정의해 사용한다.
클래스와 구조체의 선택 (Choosing Between Classes and Structures)
✅ 클래스와 구조체 모두 프로그램의 코드를 조직화 하고 특정 타입을 선언하는데 사용된다. 그리고 앞서 설명했던 것처럼 클래스 인스턴스가 인자로 사용될 때는 참조가 넘어가고 구조체는 값이 넘어간다고 했다. 그럼 언제 클래스를 사용하고 언제 구조체를 사용해야 할까?
1️⃣ 구조체의 주 목적이 관계된 간단한 값을 캡슐화 하기 위한 것인 경우
2️⃣ 구조체의 인스턴스가 참조되기 보다 복사되기를 기대하는 경우
3️⃣ 구조체에 의해 저장된 어떠한 프로퍼티가 참조되기 보다 복사되기를 기대하는 경우
4️⃣ 구조체가 프로퍼티나 메소드 등을 상속할 필요가 없는 경우
✔️ 일반적으로 위의 조건 중 1개 이상을 만족하면 구조체를 사용하는 것을 고려해 볼 수 있다.
✔️ 위에 기술된 경우를 제외한 다른 모든 경우에는 구조체가 아니라 클래스를 사용한다.
String, Array, Dictionary의 할당과 복사 동작 (Assignment and Copy Behavior for Strings, Arrays, and Dictionaries)
✅ 스위프트에서는 String, Array, Dictionary 같은 기본 데이터 타입이 구조체로 구현 돼 있다. 그렇다는 의미는 이 값을 다른 상수나 변수에 할당하거나 함수나 메소드에 인자로 넘길 때 이 값이 복사 된다는 것이다. 반면 Foundation의 NSString, NSArray, NSDictionary는 클래스로 구현 돼 있다. 그래서 이 데이터들은 항상 할당 되거나 전달될 때 복사 되지 않고 참조가 사용된다.
'Swift > Swift 기본기' 카테고리의 다른 글
10. 제네릭 (Generic) (0) | 2023.07.31 |
---|---|
09. 프로퍼티 (Properties) (0) | 2023.03.18 |
07. 열거형 (Enumerations) (0) | 2023.03.18 |
06. 클로저 (Closures) (0) | 2023.03.18 |
05. 함수 (Functions) (0) | 2023.03.18 |