값타입과 참조타입 차이점
IOS/Swift문법

값타입과 참조타입 차이점

 

swift에 자료구조들은 두가지 타입으로 존재한다

 

값 타입 (Value Type) 참조 타입(Reference Type)
- 구조체 (Struct)
- 열거체 (Enum)
- 튜플 (Tuple)
- 클래스 (Class)
- 클로저 (Closure)

 

값 타입 대표 '구조체' 와  참조 타입 대표 '클래스'를 통해 자세히 알아보자

 

 


구조체 (값 타입)

//구조체 (값 타입)
struct User {
    var ID: String
    var level: Int
    
    init(ID: String, Lv: Int) {
    	self.ID = ID
        self.level = Lv
    }
}

var userHong: User = User(ID: "hong", Lv: 20)

 

ID와 level 이라는 저장 프로퍼티가 존재하는 임의의 User 구조체를 만들었다

이를 userHong이라는 구조체 인스턴스를 생성하면 메모리는 다음과 같이 할당된다

 

 

User 구조체는 Data 메모리 영역에 생성되고,

스택 메모리 영역에 userHong이라는 인스턴스가 생성

 

그렇다면 참조 타입인 클래스는 어떻게 될까

 


클래스 (참조 타입)

//클래스 (참조 타입)
class User {
    var ID: String
    var level: Int
    
    init(ID: String, Lv: Int) {
    	self.ID = ID
        self.level = Lv
    }
}

var userHong: User = User(ID: "hong", Lv: 20)

마찬가지로 ID와 level 이라는 저장 프로퍼티가 존재하는 임의의 User 클래스를 만들었다

이를 userHong이라는 클래스 인스턴스를 생성하면 메모리는 다음과 같이 할당된다

 

마찬가지로 User 클래스는 Data 메모리 영역에 생성

하지만

클래스 (참조 타입)의 경우 heap 메모리 영역에 생성된 인스턴스의 데이터를 저장한다

stack 메모리에서는 단지 heap 영역에 있는 실제 인스턴스의 메모리 주소를 저장하고 있을 뿐

 


그래서 무슨 차이가 있을까?

 

메모리 영역이 서로 다르게 저장된다는 건 알았고, 그래서 실질적으로 무슨 차이가 발생하는지를 알아보자

 

//구조체 (값 타입)
struct UserStruct {
    var ID: String
    var level: Int
    
    init(ID: String, Lv: Int) {
    	self.ID = ID
        self.level = Lv
    }
}

//클래스 (참조 타입)
class UserClass {
    var ID: String
    var level: Int
    
    init(ID: String, Lv: Int) {
    	self.ID = ID
        self.level = Lv
    }
}

//값 타입 생성
var userStruct: UserStruct = UserStruct(ID: "hong", Lv: 20)
//값 타입 복사
var userStructCopy = userStruct

//참조 타입 생성
var userClass: UserClass = UserClass(ID: "hong", Lv: 20)
//참조 타입 복사
var userClassCopy = userClass

값 타입은 복사하면 새로운 값이 할당되어 stack 메모리에 쌓이는 걸 볼 수 있다

 

반면 참조 타입은 새로운 값이 할당되지 않고 똑같이 heap 메모리 영역에 생성된 인스턴스 메모리 주소를 복사

 

이 상태에서 복사본의 내부 프로퍼티의 값을 변경한다면 그 차이를 명확히 알 수 있을 것 이다

 

//값 타입 생성
var userStruct: UserStruct = UserStruct(ID: "hong", Lv: 20)
//값 타입 복사
var userStructCopy = userStruct

//참조 타입 생성
var userClass: UserClass = UserClass(ID: "hong", Lv: 20)
//참조 타입 복사
var userClassCopy = userClass

//값 타입 내부 프로퍼티 값 변경
userStructCopy.Lv = 15

//참조 타입 내부 프로퍼티 값 변경
userClassCopy.Lv = 15

 

똑같이 내부 프로퍼티의 값을 변경했지만

값 타입의 경우 서로 다른 인스턴스가 되어 개별적으로 값이 저장된 반면,

참조 타입의 경우 같은 메모리 주소를 가리키기(= 참조하고 있기) 때문에 기존에 생성된 인스턴스의 값이 변경된 걸 확인할 수 있었다

 

 


우리는 위 예시를 통해 아래의 특징을 알 수 있다

값 타입 = 원본 데이터 저장
참조 타입 = 원본 데이터의 메모리 주소를 저장

 

이를 생각해봤을 때

 

해당 타입들을 let (상수) 로 선언했을 때 또 하나의 차이점을 알 수 있다

 

값 타입은 원본 데이터 자체를 저장하고 있기 때문에 내부 프로퍼티를 변경할 수 없다

 

하지만

 

참조 타입은 원본 데이터의 메모리 주소를 저장하고 있고 실제 데이터는 다른 메모리 영역(heap)에 저장되어 있기 때문에

내부 프로퍼티의 값을 접근하여 변경할 수 있다는 차이점이 있다

반응형

'IOS > Swift문법' 카테고리의 다른 글

고차함수  (0) 2023.06.11