Swift로 데이터의 집합을 표현하는 방법으로는 struct, class, tuple, array등 다양합니다. 오늘은 이 중에서 주로 데이터 모델을 작성할때 사용하는 struct와 class에 대해 알아 보고자 합니다.
class와 struct는 둘 다 Property와 Function을 가지고 있으며, 프로토콜을 구현할 수 있는 공통점이 있는 타입입니다. 하지만 근본적으로 두 타입은 많이 다릅니다.
Class
class는 참조타입(Reference Type)으로 Heap Memory 공간에 할당되며, 메모리에 할당된 class는 인스턴스 또는 객체라고 불리고 있습니다. 그리고 그 인스턴스를 참조(또는 가리키는)하는 변수를 참조변수라고 합니다.
참조변수는 대입연산자(=)사용시 참조하는 인스턴스의 참조 값을 복사합니다.
Struct
struct는 값 타입(Value Type)으로 Stack, Heap, Data Memory 공간에 할당될 수 있습니다.
Struct타입의 변수는 대입연산자(=)사용시 소유한 모든 Property의 값을 복사합니다.
데이터 모델에서의 class
참조타입인 class를 데이터 모델로 사용한다면, 한 인스턴스에 대해 많은 참조가 존재하게되어 인스턴스의 데이터 변경시 참조하는 모든 곳이 영향을 받아 의도치 않은 문제가 발생 할 수 있습니다.
좀 더 풀어서 이야기해보겠습니다. Foo와 Bar가 동일한 인스턴스 fooBar를 참조하고 있고, Foo의 어느 함수 내에서 fooBar 상태를 변경했다고 가정해봅시다. Bar도 fooBar를 참조해서 사용하고 있기때문에, Foo에서 변경된 fooBar상태 변경으로 인해 Bar에서 의도치 않은 문제가 발생 할 수도 있습니다.
또한, 이렇게 발생된 문제는 참조가 많은 경우에 문제의 발생지를 찾기 어려워져 디버깅을 하기가 쉽지 않습니다.
데이터 모델에서의 struct
값 타입인 struct를 데이터 모델로 사용한다면, 위에서 거론한 class의 문제 점을 해결 할 수 있습니다. struct는 대입시 참조가 아닌 값을 복사하기 때문에, struct의 값을 변경한다해도 그 값이 다른 곳에 영향을 주지 않기 때문입니다.
하지만 struct의 덩치가 커지게되면 struct간 대입연산(=)시에 모든 값이 복사되어야 하기 때문에 속도적인 면에서 큰 비용이 발생합니다. 또한 struct의 값이 변경될 필요가 없음에도 불구하고 대입연산시 매번 새로운 메모리 공간을 할당해 프로퍼티를 복사하므로 불필요한 메모리 할당이되는 문제가 발생합니다.
위 문제는 Copy on write라는 개념을 도입해 해결이 가능합니다.
Copy on write
Copy on write (이하 COW)는 데이터 복사시 실제로 값을 복사되지 않고, 동일한 값을 참조하다가 데이터 변경이 발생될 시에 복사해 값을 변경하는 기법입니다.