클래스
클래스는 변수와 함수를 묶음으로 다룰 수 있음
클래스의 변수는 속성(property)
클래스의 함수는 메서드(method)
구조체
클래스와 다르지 않음
클래스와 구조체
클래스와 구조체 둘 다, 메모리에 찍어낸 것을 인스턴스(instance)라고 함
인스턴스는 실제로 메모리에 할당되어 구체적 실체를 갖춘 것이라는 의미
스위프트에서는 클래스의 inscance를 특별히 객체(object)라고 부름
클래스의 인스턴스(객체)
구조체의 인스턴스
열거형의 인스턴스
가장 큰 차이는 메모리 저장 방식의 차이
1) 구조체
- 값형식(Value Type)
- 인스턴스 데이터를 모두 스택(Stack)에 저장
- (복사시) 값을 전달할때마다 복사본을 생성 (다른 메모리 공간 생성)
- 스택(Stack)의 공간에 저장, 스택 프레임 종료시 메모리에서 자동 제거
2) 클래스
- 참조형식(Reference Type)
- 인스턴스 데이터는 힙(Heap)에 저장, 해당 힙을 가르키는 변수는 스택에 저장하고
- 메모리 주소값이 힙(Heap)을 가르킴
- (복사시) 값을 전달하는 것이 아니고, 저장된 주소를 전달
- 힙(Heap)의 공간에 저장, ARC시스템을 통해 메모리 관리(주의해야함)
그 외의 면에서 클래스와 구조체는 거의 동일
클래스의 기능은 거의 동일하게 구조체에서 가지고 있다고 보면 된다.
구조체는 가볍고 클래스는 무거움
클래스와 구조체의 let과 var 키워드
class PersonClass {
var name = "사람"
var age = 0
}
struct AnimalStruct {
var name = "동물"
var age = 0
}
let pclass = PersonClass()
let astruct = AnimalStruct()
pclass.name = "사람1"
pclass.name
//astruct.name = "동물1"
astruct.name
struct는 스택에 메모리구조가 생기기 때문에 변경이 불가능
class는 let으로 선언하면 메모리주소를 바꿀 수 없다는 의미
관습적인 부분들에 대한 이해
일반적으로 클래스, 구조체 선언할 때 모두
1) 속성 2) 메서드 순서대로 작성
주의점 - (참고) 클래스 내부에는 직접 메서드(함수) 실행문이 올 수 없다.
메서드 실행문은 메서드의 정의문 내에 존재해야함
처음 코딩하면서 자주 실수하는 부분이니 주의하기!
구조체, 클래스의 초기화의 의미
앞에서의 객체의 생성
초기화 메서드 / 이니셜라이저(initializer)
생성자(이니셜라이저)는 인스턴스를 만들 때 사용하는 특별한 메서드
class Dog1 {
var name: String
var weight: Int
// 생성자
init(n: String, w: Int) {
self.name = n
self.weight = w
}
func sit() {
print("\(self.name)가 앉았습니다.")
}
func layDown() {
print("\(self.name)가 누웠습니다.")
}
}
var dog1 = Dog1(n: "뭉이", w: 12)
dog1.name
dog1.weight
dog1.sit()
dog1.layDown()
var dog2 = Dog1(n: "땡이", w: 10)
초기화 메서드 / 이니셜라이저
init(파라미터)
모든 저장 속성(변수)을 초기화 해야함 (구조체, 클래스 동일) -> 모든 속성에 값을 넣어줘야 한다.
생성자 실행 종료시점에는 모든 속성의 초기값이 저장되어 있어야 함(초기화가 완료되지 않으면 컴파일 에러)
생성자의 목적은 결국 "저장속성 초기화"
클래스, 구조체, (열거형)은 모두 설계도 일뿐이고, 실제 데이터(속성), 동작(메서드)을 사용하기 위해서는 초기화 과정이 반드시 필요함.
var dog3 = Dog1(n: "흰둥이", w: 25)
// 정식문법
var dog4 = Dog1.init(n: "초코", w: 13)
인스턴스 초기화 완료 -> 메모리에 정상적으로 인스턴스가 생성
생성자(이니셜라이저)와 self키워드
인스턴스내에서 동일한 변수명, 상수명을 사용할 때 가르키는 것을 명확하게 하기 위해 self키워드 사용
init(name: String, weight: Int) {
self.name = name
self.weight = weight
}
오른쪽 파라미터 왼쪽은 인스턴스의 속성이기 때문에 self붙여주기
self키워드는 클래스 / 구조체 내에서 해당 인스턴스(자기자신)를 가르킴
초기화의 의미 - 속성이 옵셔널 타입인 경우
옵셔널타입을 가진 변수의 경우는 반드시 초기화값이 있을 필요는 없음 -> nil로 초기화되기 때문
Identity Operators(식별 연산자)
식별 연산자 - 두개의 참조가 같은 인스턴스를 가리키고 있는지를 비교하는 방법
print(dog1 === dog2)
print(dog1 !== dog2)
=== 클래스의 인스턴스가 같은지를 비교하는 연산자
구조체와 클래스의 차이
구분 | 구조체(struct) | 클래스(class) |
타입 | Value Type (값 형식) | Reference Type (참조 형식) |
메모리 관련 | 값의 저장: Stack / 복사전달 (메모리에서 자동 제거) |
값의 저장: Heap / 주소전달 (ARC로 관리) |
let / var 선언 | 인스턴스 상수(let)로 선언시 저장 속성이 전부 상수로 선언됨 |
인스턴스 상수(let)으로 선언하면 가르키는 인스턴스 고정 (저장속성은 각 let/var 선언에 따름) |
생성자 관련 | 멤버와이즈 이니셜라이저 (자동)제공 | 편의 생성자 존재 |
메서드 + 속성 | 메서드 내에서 속성 변경 원칙적으로 불가능 (mutating키워드로 가능) |
메서드 내에서 속성 변경 가능 |
소멸자 | 없음 | 있음 |
상속 가능 여부 | 불가능 | 가능(클래스가 유일) |
값형식과 참조형식
구분 | 값 형식(구조체) | 참조 형식(클래스) |
타입 | Value Type | Reference Type |
메모리상의 저장 위치 | 필요시에 항상 메모리의 값이 복사되어 전달 값의 저장: Stack |
필요시에 항상 메모리의 주소를 전달 값의 저장: Heap (주소를 Stack에 저장) |
메모리 관리 방식 | 값이 들어있는 스택의 스코프가 종료되면 메모리에서 자동 제거 |
RC(Reference Counting)을 통해 메모리를 관리 Swift에서 사용하는 ARC 모델 |
각 형식의 타입예시 | 스위프트 기본 타입(Int, String, ...) 튜플, 열거형, 컬렉션, 구조체 |
클래스, 클로저 |
언제 클래스 / 구조체를 사용해야 할까
데이터 관점에서 구조체보다 클래스가 여러개의 데이터를 묶어서 사용
클래스가 반드시 필요한 경우가 아닌 경우 구조체를 사용하도록 애플이 권장하고있음
구조체는 메모리에 오랫동안 저장하지 않음 / 상송없이, 조금 가볍게 사용
클래스는 메모리에 오랫동안 저장(관리) / 상속
- 연관된 데이터들을 단순히 캡슐화(묶는)하는 것이 목적일 때 구조체 사용
- 캡슐화한(묶은) 데이터를 참조하는 것보다 복사해서 사용하는 것이 효율적일 때 구조체 사용
- 구조체에 저장된 저장 속성들이 값 타입이며 참조하는 것보다 복사하는 것이 합당할 때 구조체 사용
- 데이터에서 상속의 구조가 필요하면 클래스 사용
- 해당 모델을 serialize 해서 전송하거나 파일로 저장할 경우가 발생하면 클래스 사용
필연적으로 클래스는 구조체보다 여러가지 면에서 속도가 느릴 수 밖에 없으므로 차이점을 명확하게 인지하고, 굳이 필요한 경우에만 클래스 사용
'iOS 관련 공부' 카테고리의 다른 글
속성(Property)과 메서드(Method) - 1 (0) | 2025.02.16 |
---|---|
초기화 (initialization) - 1 (0) | 2025.02.13 |
스토리보드 사용해서 앱 만들기 (0) | 2025.02.05 |
iOS Architecture / Framework (0) | 2025.02.02 |
열거형(Enumeration) (1) | 2025.02.01 |