- 1.18일 스터디 준비 자료를 만들면서 작성해 본 글이다.
- 우선적으로 짧은 글로 설명할 수 있는 부분에 대해선 PDF 파일로 제작하였고, 해당 글에서는 "struct", "class"의 차이점을 알아봄과 동시에 메모리 관련 내용도 살펴볼 예정이다.
- 단, 현재까지 학습했던 내용을 기반으로 작성하는 글이라 추후 새로 배운 개념들에 대한 적용할 예정이다.
Class, Struct
- 해당 링크 사이트를 참고했습니다.
구조체와 클래스 (Structures and Classes)
Swift에서 구조체와 클래스의 공통점
- 값을 저장하는 속성(프로퍼티) 정의
- 기능 제공을 위한 메서드 정의
- 서브 스크립트 구문을 사용하여 값에 접근을 제공하는 서브 스크립트 정의
- 초기화 상태를 설정하기 위한 초기화 정의
- 기본 구현을 넘어 기능적 확장을 위한 확장
- 특정 종류의 표준 기능을 제공하는 프로토콜 준수
- 클래스에는 구조체에 없는 추가적인 기능이 존재
- 상속을 사용하면 한 클래스가 다른 클래스의 특성을 상속할 수 있음.
- 타입 캐스팅을 사용하면 런타임에 클래스 인스턴스의 타입을 확인하고 해석할 수 있음
- 초기화 해제 구문을 사용하면 클래스의 인스턴스가 할당된 리소스를 해제할 수 있도록 함
- 참조 카운팅은 하나 이상의 클래스 인스턴스 참조를 허락함
더보기
- 설명
- 타입 캐스팅(Type Casting)은 Swift에서 런타임에서 인스턴스의 실제 타입을 확인하거나 다른 타입으로 캐스팅하는 기능을 말함
- 런타임에서 타입 확인(Type Checking)
- 특정 인스턴스가 어떤 클래스의 인스턴스인지 확인하는 것. 이를 통해 런타임 중에 동적으로 객체의 타입을 확인할 수 있음
- 다운캐스팅(Downcasting)
- 상위 클래스 타입으로 선언된 인스턴스를 하위 클래스 타입으로 캐스팅하는 것을 말함.
- 이때 as?나 as! 연산자를 사용. as?는 옵셔널 타입으로 캐스팅하며, 캐스팅에 실패하면 nil을 반환. as!는 강제 캐스팅이며, 캐스팅에 실패하면 런타임 오류가 발생.
if someInstance is SomeClass { // 런타입에서 타입 확인
// someInstance가 SomeClass의 인스턴스인 경우
print("It's an instance of SomeClass")
} else {
// someInstance가 SomeClass의 인스턴스가 아닌 경우
print("It's not an instance of SomeClass")
}
// 다운캐스팅
let someInstance: SomeSuperclass = SomeSubclass()
if let downcastedInstance = someInstance as? SomeSubclass {
// 다운캐스팅 성공
print("It's downcasted to SomeSubclass")
} else {
// 다운캐스팅 실패
print("It's not downcasted to SomeSubclass")
}
- 클래스가 지원하는 추가 기능은 복잡성이 증가
- 일반적인 지침으로는 추론하기 쉬운 구조체를 선호하고 적절하거나 필요할 때 클래스를 사용
- Code convention
- 타입 : UpperCamelCase
- 프로퍼티, 메서드 : lowerCamelCase
- 구조체와 열거형은 값 타입 (Structures and Enumerations Are Value Types)
- 클래스는 참조 타입
- ARC로 메모리 관리를 진행
- 코드를 통해 살펴보자
class UserClass {
var rc: Int = 0
deinit {
print("free!\n")
}
}
struct UserStruct {
var rc: Int = 0
}
var userClass1 = UserClass()
var userClass2 = userClass1
var userClass3 = userClass1
userClass2.rc = 100
print(userClass1.count) // 100
print(userClass3.count) // 100
var userStruct1 = UserStruct()
var userStruct2 = userStruct1
var userStruct3 = userStruct1
userStruct2.rc = 1
userStruct3.rc = 2
print(userStruct1.rc) // 0
print(userStruct2.rc) // 1
print(userStruct3.rc) // 2
Choosing Between Structures and Classes | Apple Developer Documentation
- Use structures by default.
- Use classes when you need Objective-C interoperability.
- Use classes when you need to control the identity of the data you’re modeling.
- Use structures along with protocols to adopt behavior by sharing implementations.
ARC, Retain Cycle
// ARC
var arc1: UserClass? = UserClass()
print(CFGetRetainCount(arc1)) // 변수에 할당한 객체의 경우 2가 기본 값
var arc2 = arc1
print(CFGetRetainCount(arc1)) // 참조 카운트가 1 증가한 3이 됩니다.
arc1 = nil
print(CFGetRetainCount(arc2)) // 참조 카운트가 1감소하여 2가 됩니다.
arc2 = nil // 참조 카운트가 1 감소하여 더 이상 참조하는 곳이 없으모르 deinit이 실행됩니다.
- 자세한 사항은 아래 두 사이트를 참고하자
- 추후, arc에 대한 강의를 수강한 후 다시 정리할 예정이다.
- 자동 참조 카운팅 (Automatic Reference Counting)
그래서 클래스, 구조체의 구체적인 차이가 뭔데?
- 구조체
- Stack 할당
- 스레드들은 각각 독립적인 Stack 공간을 가지고 있기 때문에 상호 배제(mutual exclusion)를 위한 자원이 필요하지 않음 → 스레드로부터 안전(race condition이 날 확률이 적다)
- 오버헤드가 적음(주소 참조해서 들어가서 값을 확인하고 하는 과정이 생략되다 보니 빠르다)
- Stack 할당
- 클래스
- Heap 할당
- 오버헤드가 높음. 메모리 할당, 해제도 필요, 참조해서 데이터를 확인하는 과정이 stack과 달리 필요하다.
- 스레드가 공유하는 메모리 공간이기 때문에 스레드로부터(race condition)으로부터 안전하지 않음.
- 즉, 이를 관리해 주기 위한 lock과 같은 자원도 필요
- Heap 할당
반응형
'iOS > Swift' 카테고리의 다른 글
Swift No.16 (0) | 2024.01.17 |
---|---|
Swift No.15 (0) | 2024.01.17 |
Swift No.13 (0) | 2024.01.14 |
Swift No.12 (0) | 2024.01.13 |
Swift No.11 (0) | 2024.01.13 |