Struct and Class
구조체와 클래스는 하나의 큰 코드 블록이며, 구조체와 클래스에서 정의된 변수와 상수는 프로퍼티라고 하고, 함수는 메소드라고 한다.
정리하면
- 프로퍼티 - 구조체와 클래스 내부에 정의되어 있는 변수 및 상수
- 메서드 - 구조체와 클래스 내부에 정의되어 있는 함수
구조체와 클래스의 공통적인 부분은
- 값을 저장하기 위해 프로퍼티를 정의할 수 있다.
- 기능이나 동작을 구현하기 위해 메소드를 정의할 수 있다.
- 서브스크립트 문법을 통해 구조체/클래스가 갖는 값에 접근 가능하다.
- 초기화될 때의 상태를 이니셜라이저를 통해 정의할 수 있다.
- 새로운 기능을 추가하기위해 익스텐션으로 확장할 수 있다.
- 특정 기능을 실행하기 위해 특정 프로토콜 사용 가능하다.
차이점으로는
- 구조체는 상속 불가능, 클래스는 상속 가능하다.
- 구조체는 값 형식, 클래스는 참조 형식이다.
- 타입 캐스팅은 클래스 인스턴스, 구조체에서 사용 가능하다.
- Deinitializer(소멸자)는 클래스 인스턴스에서만 사용 가능하다.
인스턴스 - 구조체나 클래스를 통해서 생성된 하나의 객체를 인스턴스라고 한다.
Struct
구조체는 메모리 구조에서 보면 스택이라는 메모리 저장공간에 값을 저장한다. 그리고 값을 전달할때마다 복사본을 생성한다.
기본 문법 📝
struct StructName {
property
method
initializer
subscript
}
구조체의 이름은 UpperCamelCase로 선언하고 나머지 프로퍼티와 메소드들은 lowerCamelCase로 선언한다.
struct Car {
var name: String
var number: Int
func maker () {
print("Audi")
}
}
// 새로운 메모리공간이 생기고 차의 이름과 번호가 생성되었다.
let p = Car(name: "A6", number: 7777)
// 속성은 인스턴스의 이름으로 접근한다.
p.name
p.number
// 메소드도 인스턴스의 이름으로 접근한다.
p.maker()
Class
클래스는 힙이라는 메모리 공간에 값을 저장하고, 스택에는 힙에 저장되어있는 값의 주소를 저장한다. 값을 전달하면 복사본은 생성하지 않고 주소만 전달한다.
기본 문법 📝
class ClassName {
property
method
initializer
subscript
}
구조체와 이름짓는 방법, 인스턴스 생성하는 방법과 속성에 접근하는 방법도 구조체와 동일하다.
class Car {
var name: String
var number: Int
// 프로퍼티에 초기값을 선언해주지 않으면 에러남
init(name: String, number: Int) {
self.name = name
self.number = number
}
func maker () {
print("Audi")
}
}
// 새로운 메모리공간이 생기고 차의 이름과 번호가 생성되었다.
let p = Car(name: "A6", number: 7777)
// 속성은 인스턴스의 이름으로 접근한다.
p.name
p.number
// 메소드도 인스턴스의 이름으로 접근한다.
p.maker()
Initializer Syntax
구조체와 클래스의 인스턴스는 생성될때 반드시 모든 저장프로퍼티에 초기값이 저장되어있어야한다. 저장프로퍼티에 초기값이 없을때 이니셜라이저를 호출하여 초기값을 저장할 수 있다. 키워드로 init()을 사용한다.
이니셜라이저 선언 문법
init(parameters) {
statements(생성자 초기화)
}
Struct Initializer
- 기본 이니셜라이저(Default Initalizers)
struct Car { var name: String = "A6" var number: Int = 7777 }
// 인스턴스 생성 (기본 이니셜라이저)
let model = Car()
저장 프로퍼티에 초기값이 전부 있는 경우에는 기본 이니셜라이저를 사용할 수 있다.
- 멤버와이즈 이니셜라이저(Memberwise Initalizers)
프로퍼티의 이름으로 파라미터를 가지는 이니셜라이즈로 저장 프로퍼티에 초기값이 저장되어 있지 않은 경우에 사용한다. 클래스에서는 사용불가능
```swift
struct Car {
var name: String
var number: Int
}
// 인스턴스 생성 (멤버와이즈 이니셜라이저)
let model = Car(name: "A6", number: 7777)class Initializer
클래스는 구조체와는 다르게 초기값이 반드시 할당되어 있어야 한다.
class Car {
var name: String
var number: Int
}
저장프로퍼티에 초기값이 할당되어 있지 않으면 에러가 발생한다.
class Car {
var name: String = "A6"
var number: Int = 7777
}
초기 값을 할당해주거나
class Car {
var name: String
var number: Int
init() {
name = "A6"
number = 7777
}
}
이니셜라이저 선언을 통해 초기값을 반드시 할당해 주어야 한다.
class Car {
var name: String
var number: Int
init(name: String, number: Int) {
self.name = name
self.number = number
}
}
// 새로운 인스턴스 생성
let car = Car(name: "A6", number: 7777)
car.name // A6
car.number // 7777
파라미터를 받는 이니셜라이저를 생성하면 인스턴스 생성시 파라미터를 전달받아 저장프로퍼티에 할당된다.
값형식과 참조형식의 차이
값 형식에는 구조체, 열거형, 튜플이 있으며, 참조 형식에는 클래스, 클로저가 있다.
먼저 구조체에서 값형식을 알아보자
struct Car {
var name: String = "A6"
var number: Int = 7777
}
var car = Car()
var car2 = car
car2.name = "X6"
car2.name // X6
car.name // A6
var car = Car()
car 인스턴스를 생성하면 "A6"와 7777로 초기화된 값들이 저장된다.
var car2 = car
그리고 새로운 car2 변수로 car에 저장되어 있는 초기값들을 저장시키면 car, car2 두개의 메모리공간이 생성되었다. 즉 각각의 인스턴스인 것이다.
car2.name = "X6"
car2.name // X6
car.name // A6
여기서 car2에 저장되어있는 name의 값을 "X6"로 바꾸고 각각의 변수에 저장되어 있는 값을 확인해보면 car.name은 "A6"로 변경되지 않았고, car2.name만 "X6"로 변경되었다.
이렇게 값 형식은 값을 전달할때마다 새로운 메모리에 할당된 복사본이 전달된다. 메모리 구조에서 보면 스택이라는 메모리 저장공간에 값을 저장하고, 값을 전달할때마다 복사본을 생성한다.
다음은 클래스 참조 형식에 대해 알아보자
class Car {
var name: String
var number: Int
init(){
name = "A6"
number = 7777
}
}
let car = Car()
let car2 = car
car2.name = "X6"
car2.name // X6
car.name // X6
let car = Car()
car 인스턴스를 생성하면 "A6"와 7777로 초기화된 값들이 저장된다.
let car2 = car
위 코드의 결과를 보면 구조체와 동일하게 새로운 car2 상수로 car에 저장되어 있는 초기값들을 저장시켰다.
car2.name = "X6"
car2.name // X6
car.name // X6
car2에 저장되어있는 name의 값을 "X6"로 바꾸고 각각의 상수에 저장되어 있는 값을 확인해 보면, 이번엔 car.name에 저장된 값까지 "X6"로 변경된것을 볼 수 있다.
이렇게 참조형식은 힙이라는 메모리 공간에 값을 저장하고, 스택에는 힙에 저장되어있는 값에 주소를 저장하기 때문에 값을 전달하면 복사본은 생성하지 않고 주소만 전달해 원본 값까지 같이 바뀐다.
여기서 중요한점은 구조체와 클래스에서 저장프로퍼티가 변수로 선언되어있을때 인스턴스를 상수로 선언해버리면
struct Car {
var name: String = "A6"
var number: Int = 7777
}
let car = Car()
car.name = "X6" // 에러 발생
구조체에서는 인스턴스 상수를 변수로 바꿔주어야 값 변경이 가능하다.
class Car {
var name: String = "A6"
var number: Int = 7777
}
let car = Car()
car.name = "X6"
클래스에서는 상수로 선언되어있어도 값 변경이 가능하다.
클래스와 구조체, 나머지 구현 조건
- 객체지향 프로그래밍에서는 대부분 참조형식인 클래스로 구현한다.
- 상대적으로 적은 데이터를 저장하고 상속이 필요하지 않은경우에 값형식으로 구현한다.
- 값이 전달될때마다 복사본이 생성되야할때도 값형식으로 구현한다.
- 연관된 상수 그룹을 표현할땐 열거형으로 구현한다.
- 코드내에서 한번만 사용되는 형식은 튜플로 구현한다.
- 나머지 값형식은 구조체로 구현한다.
'Swift > Swift문법' 카테고리의 다른 글
| Swift문법 - Subscript (0) | 2023.03.26 |
|---|---|
| Swift문법 - Properties (0) | 2023.03.19 |
| Swift문법 - Enumeration (0) | 2023.03.05 |
| Swift문법 - Collection (0) | 2023.02.26 |
| Swift문법 - String Options (0) | 2023.02.19 |