Class와 Struct

DevMinion·2022년 7월 13일
1

Class와 Struct의 딥한 차이를 알아보쟈🙌
지금까지 Class와 Struct의 차이로는 Class는 ARC로 메모리관리를 한다. Class는 reference type이며 Struct는 value type이다. 까지만 알고 있었지만 보다 딥한 차이를 알지 못해 공부하고자 글로 남긴다.

Class와 Struct의 공통점

  • Class와 Struct 모두 값을 저장하는 프로퍼티를 정의할 수 있으며, 메소드를 정의할 수 있다.
  • extension을 사용하여 기능을 확장할 수 있다.
  • Protocol을 채택할 수 있다.
  • 생성자(init())을 사용하여 초기값을 설정할 수 있다.
  • "."을 사용하여 내부값에 접근할 수 있다.

Class와 Struct의 차이점

Class

  • reference type이다.
  • ARC를 통해 메모리를 관리한다.
  • reference type이기에 여러 변수에 인스턴스를 할당한 후 한 인스턴스의 값을 변경하면 할당한 모든 인스턴스의 값이 변경된다. (같은 메모리 주소를 복사하기에)
  • 상속이 가능하다.
  • type casting을 통해 런타임에서 인스턴스의 타입을 확인할 수 있다.
  • deinit을 통해 메모리 할당을 해제할 수 있다. 뒤에서 자세히 다룬다.

Struct

  • value type이다.
  • value type이기에 여러 변수에 구조체를 할당한 후 한 변수의 값을 변경해도 다른 변수의 값이 변경되지 않는다. (값 자체를 복사하기에)

직접 코드로 확인해보자.

import UIKit
import Foundation

class MainClass {
    var number: Int = 0
}

struct MainStruct {
    var number: Int = 0
}

//MARK: - 클래스
var class1 = MainClass()
var class2 = class1
var class3 = class1
class3.number = 10

//MARK: - 구조체
var struct1 = MainStruct()
var struct2 = struct1
var struct3 = struct1
struct3.number = 10

print("class1 number:",class1.number)
print("class2 number:",class2.number)
print("class3 number:",class3.number)
print("struct1 number:",struct1.number)
print("struct2 number:",struct2.number)
print("struct3 number:",struct3.number)

결과는,

이렇게 reference type인 Class는 하나의 값만 변경해도 모든 변수의 프로퍼티 값이 바뀐것을 확인할 수 있다.
value type인 Struct는 값 자체를 복사하기에 변경한 변수의 프로퍼티 값만 바뀐것을 확인할 수 있다.
이 말인 즉, Class는 하나의 메모리를 공유하지만 Struct는 새로운 메모리를 할당한다는 뜻이기도 하다.

var과 let.

자 위의 코드에서 Class와 Struct의 인스턴스를 할당받은 변수들을 상수로 모두 바꾼다면?

//MARK: - 클래스
let class1 = MainClass()
let class2 = class1
let class3 = class1
class3.number = 10 // <- 상수 변경 가능?

//MARK: - 구조체
let struct1 = MainStruct()
let struct2 = struct1
let struct3 = struct1
struct3.number = 10 // <- 상수 변경 가능?

분명 let은 초기값 이후에 다른 값으로 바꿀 수 없다. Class 부분부터 결과를 확인해보자.

정상적으로 동작한다!
상수로 선언했어도 값을 변경할 수 있는 이유는 이제는 말하기도 지겹지만 상수 자체를 변경한 것이 아닌 상수가 가르키는 메모리 주소의 값을 변경한 것이기 때문이다. 이 또한 reference type이기에 가능!

그렇다면 Struct는 어떨까.

오류를 뱉는다!
당연히 value type인 Struct는 값 자체를 변경하려 시도하는 것이기에 Xcode가 나서서 변경할 수 없도록 혼내준다.

ARC(Automatic Reference Counting)

Class와 Struct의 차이중 Class만이 갖는 특성이 있다. 바로 ARC로 메모리를 관리한다는 것이다. 앞서 보았듯 ARC의 사용 가능여부는 reference/value type의 차이에서 온다. Class는 reference type으로 ARC의 뜻 그대로 RC(Reference Counting)가 가능하다. 당연히 value type인 Struct는 RC를 사용하여 관리할 수 없는 것이다.
ARC는 다른 게시글에서 보다 자세히 다뤄보도록 하겠다!
ARC&Memory👈

Stack할당과 Heap할당

지금까지 알고있던 지식으로는 Reference type은 Heap영역에, Value type은 Stack영역에 할당한다고 알고 있었다. 하지만 이는 틀렸다. Heap영역에는 여러 이유로 Reference type과 Value type 모두 할당될 수 있다. 차근차근 알아보자.

Stack영역

기본적으로 Stack영역에는 Struct 즉, Value type이 할당된다. Stack 자료구조를 사용하기 때문에 PUSH와 POP으로 메모리를 할당, 해제할 수 있다. 또 쓰레드들은 각각의 독립적인 Stack공간을 갖고 있어 쓰레드로부터 안전하다. 결국 이러한 차이로 Stack을 사용하는 것이 Heap을 사용하는 것보다 빠르다. 이래서 Apple이 Struct를 권장하나?

Heap영역

Heap영역에는 Value type만 저장되는 Stack영역과는 다르게 Reference type, Value type 모두 저장될 수 있다. Stack과는 다르게 Heap은 참조를 계산해야 한다. 본래 Heap은 'malloc'과 같은 동적 할당으로 메모리를 할당하고, 'free' 등으로 할당을 해제해줘야 한다. 하지만 Swift에서는 ARC를 통해 프로그래머가 직접 할당을 해제해주지 않아도 되며, 클래스 인스턴스나 클로저와 같은 Reference type의 값은 알아서 할당하여 준다. 이 얼마나 편한가.

Class와 Struct. 언제 무엇을 사용할까?

Apple의 Documantation에 따르면, 아래의 상황에 해당될 경우 Struct를 사용하길 권장한다.

  • 연관된 간단한 값의 집합을 캡슐화하는 것만이 목적일 때
  • 캡슐화한 값을 참조하는 것보다 복사하는 것이 합당할 때
  • 구조체에 저장된 프로퍼티가 Value type이며 참조하는 것보다 복사하는 것이 합당할 때
  • 다른 타입으로부터 상속받거나 자신을 상속할 필요가 없을 때

References(Thx🤙)

[Stack & Heap] - 상어의 개발 블로그
[Class와 Struct] - Dev_Pingu
[Choosing Between Structures and Classes] - Apple

profile
iOS를 개발하는 미니언

0개의 댓글