class와 struct의 차이점은?
클래스과 구조체 (Classes and Structures)
The Swift Language Guide(한국어) - 클래스와 구조체
class와 struct의 공통점
- 값을 저장하기 위한 프로퍼티를 정의할 수 있다.
- 기능을 제공하기 위한 메서드를 정의할 수 있다.
- .를 사용하여 특정 값에 접근할 수 있다.
- 초기 상태를 설정할 수 있는 initializer를 정의할 수 있다.
- 기본 구현에서 기능을 확장할 수 있다.
- 프로토콜을 사용할 수 있다.
class와 struct의 차이점
class
- 참조 타입이다.
- ARC로 메모리를 관리한다.
- 상속이 가능하다.
- 타입 캐스팅: 런타임에서 클래스 인스턴스의 타입을 확인할 수 있다.
- 소멸자: deinit을 사용하여 메모리 할당을 해제시킬 수 있다.
- 참조 카운트: 클래스 인스턴스에 하나 이상의 참조가 가능하다.
struct
- 값 타입이다.
- 구조체 변수를 새로운 변수에 할당할 때마다 새로운 구조체가 할당된다.
class 참조 예제
NewClass 클래스를 작성한다.
class NewClass {
var count = 0
}
class1을 생성하고 class1을 이용해 class2를 생성한다.
var class1 = NewClass()
var class2 = class1
class2의 count값을 변경하였지만 class1의 count값도 변경된 것을 확인할 수 있다. 클래스는 참조 타입이기 때문이다.
class2.count = 1
print(class1.count) // 1
struct 값 타입 예제
NewStruct 구조체를 작성한다.
struct NewStruct {
var count = 0
}
struct1을 생성하고 struct1을 이용해 struct2를 생성한다.
var struct1 = NewStruct()
var struct2 = struct1
struct2의 count값을 변경하였지만 struct1의 count값은 변경되지 않았다. 구조체는 값 타입이기 때문이다.
struct2.count = 1
print(struct1.count) // 0
class ARC 예제
NewClass에 소멸자를 추가한다.
class NewClass {
var count = 0
deinit {
print("할당 해제")
}
}
참조 카운트의 기본값은 2이다. classARC2는 classARC1도 참조하고 있기에 참조 카운트가 1 추가된다.
var classARC1: NewClass? = NewClass()
print(CFGetRetainCount(classARC1)) // 2
var classARC2: NewClass? = classARC1
print(CFGetRetainCount(classARC2)) // 3
참조되는 모든 값들을 해제하였기 때문에 deinit이 실행된다. "할당 해제"가 출력된 것을 확인할 수 있다.
classARC1 = nil
print(CFGetRetainCount(classARC2)) // 2
classARC2 = nil // deinit 실행됨
class retain cycle 예제
클래스 StrongRefClassA와 StrongRefClassB를 작성한다.
class StrongRefClassA {
var classB: StrongRefClassB?
deinit {
print("A 할당 해제")
}
}
class StrongRefClassB {
var classA: StrongRefClassA?
deinit {
print("B 할당 해제")
}
}
클래스 classA와 classB를 생성한다. 참조 카운트의 기본값인 2가 출력된다.
var classA: StrongRefClassA? = StrongRefClassA()
var classB: StrongRefClassB? = StrongRefClassB()
print(CFGetRetainCount(classA)) // 2
print(CFGetRetainCount(classB)) // 2
classA의 classB는 classB를 참조하도록 하고, classB의 classA는 classA를 참조하도록 한다. 참조 카운트가 증가한다.
classA?.classB = classB
classB?.classA = classA
print(CFGetRetainCount(classA)) // 3
print(CFGetRetainCount(classB)) // 3
classA와 classB를 지웠지만 deinit이 실행되지 않았다. 이렇게 되면 메모리 누수가 발생하게 된다.
classA = nil
print(CFGetRetainCount(classB?.classA)) // 2
classB = nil // deinit 실행되지 않음
class 메모리 누수 해결
weak 참조를 사용하면 retain cycle을 방지할 수 있다.
class StrongRefClassA {
weak var classB: StrongRefClassB?
deinit {
print("A 할당 해제")
}
}
class StrongRefClassB {
weak var classA: StrongRefClassA?
deinit {
print("B 할당 해제")
}
}
var classA: StrongRefClassA? = StrongRefClassA()
var classB: StrongRefClassB? = StrongRefClassB()
print(CFGetRetainCount(classA)) // 2
print(CFGetRetainCount(classB)) // 2
classA?.classB = classB
classB?.classA = classA
print(CFGetRetainCount(classA)) // 2
print(CFGetRetainCount(classB)) // 2
classA = nil // deinit 실행됨
classB = nil // deinit 실행됨
메모리 할당 차이
이러한 특징들 때문에 구조체와 클래스는 메모리에 저장되는 위치가 다르다. 구조체는 언제 생기고 사라질 지 컴파일 단계에서 알 수 있기에 메모리의 stack 공간에 할당된다. 반면 클래스는 참조가 어디서 어떻게 될 지 모르기에 Heap 공간에 할당된다.
Stack 할당
Stack은 LIFO(Last In First Out)로 가장 마지막에 들어간 객체가 가장 먼저 나오는 자료구조이다. 하나의 명령어로 메모리를 할당, 해제할 수 있다. 또한 컴파일 단계에서 언제 생성되고 해제되는지 알 수 있는 구조체와 같은 값 타입이 저장되게 된다.
스레드들은 각각 독립적인 Stack 공간을 가지고 있기 때문에 상호 배제를 위한 자원이 필요하지 않는다. 즉 스레드로부터 안전하다. 이러한 특징 때문에 Stack의 값을 사용하는 것이 Heap의 값을 사용하는 것보다 빠르다.
*스레드란 프로세스의 작업흐름의 단위를 말한다.
*컴파일이란 사람이 보기 편하게 만든 소스코드를 컴퓨터가 이해할 수 있는 기계어 구조로 변환하는 과정을 의미한다.
Heap 할당
Heap에는 컴파일 단계에서 생성돠 해제를 알 수 없는 참조 타입의 객체가 할당된다. 클래스 객체가 힙에 할당된다. Heap은 참조 계산도 해야 하기에 메모리 할당과 해제가 하나의 명령어로 처리되지 않는다.
Heap은 스레드가 공유하는 메모리 공간이기에 스레드로부터 안전하지 않는다. 이를 관리하기 위한 lock과 같은 자원도 필요하게 되고 이는 곧 오버 헤드로 이어지게 된다.
*오버헤드란 어떤 처리를 위한 간접적인 처리 시간, 메모리 등을 의미한다.
언제 클래스를 쓰고 언제 구조체를 쓸까?
단순한 데이터 값을 보유하기 위해서는 구조체를 쓴다. 그리고 메모리의 스택은 크기가 크지 않기에 작은 값을 갖는 데이터를 처리할 때 구조체를 사용한다. 반면 Object-C와 상호 운용성을 원할 때는 클래스를 사용한다.
참고 사이트 주소
Author And Source
이 문제에 관하여(class와 struct의 차이점은?), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@leeesangheee/Swift-class와-struct의-차이점저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)