값(Value)형태와 레펀러스(Reference) 참조 형태의 차이를 가진 Struct와 Class에서의 let 선언과 var 선언의 차이의 핵심을 알아보겠습니다 ~
class T1 {
var name: String?
init(_ name: String?){
self.name = name
}
}
var a = T1("1") //T1("1") 주소 100이라고 가정
a = T1("2") //T1("2") 주소 102이라고 가정
//새로운 인스턴스 주소를 가리킬 수 있음
let b = T1("immutable")
//새로운 인스턴스 주소를 가리킬 수 없음
//b.name = "변경가능"
//heap 인스턴스에서 변수를 가진 name 영역은 변경가능
let c = b
let d = b
b = T1("변경")
//에러발생
print(d.name)
//immutable 출력
먼저 위의 코드에서 a,b,c,d 를 ViewController 안에 있는 지역변수라고 가정하겠습니다.
그렇다면 지역 변수 a는 heap 영역의 T1 Instance (주소 100이라고 가정) 를 가리키고 있습니다. 또한 a 인스턴스는 var 형태로 선언되었기 때문에 , 새로운 T1 클래스 인스턴스의 주소(102) 를 가리킬 수 있습니다.
Class에서는 스택영역에서 heap 인스턴스를 가리키는 주소를 변경할 수 있느냐 없느냐의 차이를 가집니다.
let으로 선언된 b 는 새로운 인스턴스의 주소를 가리킬 수 없습니다. 즉, heap 영역을 가리키는 주소변경이 불가능합니다. 하지만 heap 영역내의 변수인 name의 변경은 가능합니다.
그렇다면 다음과 같은 상황은 어떨까요?
class T1 {
var name: String?
init(_ name: String?){
self.name = name
}
}
var a = T1("1")
a = T1("2")
var b = T1("immutable")
let c = b
let d = b
b = T1("test instance")
print(b.name) //test instance 출력
print(d.name) //immutable
print(c.name) //immutable
b를 참조하는 c,d 는 let으로 상수로 선언되어있습니다. 하지만 T1인스턴스를 가리키는 b는 var 로 선언되었습니다. 즉, 새로운 인스턴스 주소를 가리킬 수 있습니다.
이 형태에서는 c와 d는 기존의 immutable 인스턴스를 가리키고 있으며, var b는 새로운 주소를 가진 T1("test instance")를 가리키게 됩니다.
자, 이제 구조체 Value 형태로 넘어가 봅시다 ~
struct Value {
var value = 0
var name: String?
init(name: String?) {
self.name = name
}
func printValue() {
print(value)
}
mutating func changeValue(v: Int) {
value = v
}
}
let a = Value(name: "Damwon")
a.name = "변경할래용" // 에러
a.changeValue(v: 400) // mutating keyword가 붙어있어도 에러
a = Value(name: "T1")
//Stack 영역에서의 새로운 주소 변경이 불가능하다.
새로운 인스턴스의 변경은 Class와 동일해 보인다. 하지만 내부 데이터 변경은 완전히 다르다.
Class에서는 let으로 선언된 인스턴스의 변수의 수정이 가능했지만, Struct는 stack에 저장되는 값 데이터 이므로 구조체 안의 변수가 var 이여도 값 변경이 불가능하다.
var a = Value(name: "Damwon")
a.name = "변경할래용"
a.changeValue(v: 400)
//var a 선언이므로, 모두 값 변경 가능
반면, 위와 같이 var 선언시 값 변경과 mutating func을 이용해 내부 값을 변경할 수 있다.
var a = Value(name: "Damwon")
let b = a
let c = a
a = Value(name: "T1")
print(a)
print(b)
print(c)
//출력결과:
// Value(value: 0, name: Optional("T1"))
// Value(value: 0, name: Optional("Damwon"))
// Value(value: 0, name: Optional("Damwon"))
생성된 인스턴스 주소의 변경 가능성, 생성된 인스턴스의 내부 값 변경이 필요한지 안 필요한지 그리고 값 과 레퍼런스타입을 잘 구별하여 프로젝트에 적응해야 합니다 !.!
'Swift information' 카테고리의 다른 글
우아한 Model Data 처리 (1) (0) | 2022.06.11 |
---|---|
클로저 - Capturing Values와 ARC (0) | 2021.12.03 |
ARC 시리즈 2 - SideTable (0) | 2021.11.04 |
ARC 시리즈 1 - Retatin Cycle 과 Reference Count (0) | 2021.11.02 |