[iOS] ViewModel은 struct로 만들어야할까 class로 만들어야할까?

Youth·2023년 9월 10일
2

TIL

목록 보기
10/21

오늘은 struct와 class에 대한 주제를 가져와봤습니다!

본론으로 들어가기전에 어쩌다 이런 주제로 포스팅을 하게되었는지에 대해서 말해보려합니다

제가 WWDC 스터디를 하고 있는데요
Understanding Swift performance라는 영상을 보면
(이 영상은 진짜 swift의 근본에 대한 영상입니다 꼭 보시길 추천 드립니다)

struct와 class의 실행에 관한 이야기가 나옵니다 뭐.. 특정상황에서 얼마나 빠른지를 비교해주거든요

이 영상을 처음 봤을때 제가 들었던 생각은 뭔가 대부분의 상황에서 구조체를 사용하는게 좋을거같은데?라는 생각이 들었습니다

그래서 왠만한 상황에서는 아무생각없이 구조체를 채택해서 썼기도 했고 딱히 큰 문제가 발생했던적도 없었습니다 아마도 제가 진행했던 프로젝트의 규모의 구조의 특성상 운이 좋게도 아무런 문제가 발생하지 않았던거일수도 있습니다

그런데 MVC에서 MVVM으로 코드 리팩터링을 진행하고 있는데 ViewModel을 만들때 문득 내가 지금까지 레퍼런스로 봐왔던 ViewModel은 class로 되어있었는데 과연 struct로 만들어도 괜찮은걸까라는 생각이 들었습니다


우선은 struct로 만들어봐

예전의 저라면 누군가 저에게 이런 고민을 털어놨을 때

상속을 할일이 없으면 구조체로 만들어봐 우선은

이라고 대답했을거같아요

struct와 class의 기능적으로 가장 큰 차이점은 상속의 가능 여부라고 생각하는데 구조체는 상속은 불가능해도 protocol이라는 도구가 있기때문에 우리가 원하는 역할을 수행해줄 수 있다고 생각했습니다

struct와 class의 가장 큰 차이점이라고 하면 역시 value type과 referece type이라고 할 수 있습니다
하지만 이 차이또한 객체를 가지고 있는 변수를 copy할때가 아니라면 크게 와닿지 않기도 했습니다

게다가 제가 했던 프로젝트들에서는 viewModel을 공유할일 없이 단순히 ViewController하나에 unique한 ViewModel 하나가 있는 구성이 100%였기 때문에 굳이 ViewModel을 class로 할 이유가 없다고 생각을 했습니다

그런데 swift문서에 struct와 class의 choice에 관한 문서가 있더라고요

그래서 처음에 제목을 보고

역시 구조체를 기본적으로 채택하는게 맞구나

라고 생각을 했었습니다
제가 생각한 이유가 100퍼센트 일치하지는 않더라도 어느정도 일맥상통하지 않을까라는 생각을 했습니다

근데 자세히 읽어보면

common한 종류의 data를 표현하는데 struct를 쓰라고 합니다
우리가 일반적으로 data를 표현하기 위해서 Model을 만들어서 쓰는데

사실 Model은 보통 struct로 만들어서 쓰잖아요?
아마 그 근거가 이 문장과 문단에 담겨있는것 같습니다

그렇게 생각하면 이 문단이 Model을 제외한 객체나 인스턴스에 대한 선택의 기준을 제시하고 있는게 아니라는 생각이 들었습니다


Control Identity

지금 보고있는 아티클의 바로 아래 문단으로 가면 이런 문단이 있습니다

좀 많이 길지만 핵심은 이겁니다 Identity
identity는 아마 여러분들도 뜻을 아시겠지만 저는 여기서 Identity를 정확히 어떻게 해석해야할지 몰라서 구글에 검색을 해보니 이런 단어뜻도 가지고 있더라고요

Identity : 자기 동일성

그러면 이런 의미겠네요
우리가(자기동일성이 뭔지는 아직 모르겠지만)자기동일성을 컨트롤할 필요가 있으면 class를 사용해라

제가 생각했을떄 identity는 이런의미인거같습니다

class PayService {
    var amount = 0
   	func pay(_ input: Int) {
        self.amouny += input
    }
}

let motherPay = PayService()
motherPay.pay(100)
print(motherPay.amouny)
///결과 : 100

let fatherPay = motherPay
fatherPay.pay(200)
print(fatherPay.amount)
///결과 : 300

class는 기본적으로 reference type입니다 객체자체가 복사되어서 저장되는게 아니라 애초에 주소값을 저장하기때문에 두 객체가 하나의 class를 공유하고 있는 상황이 됩니다

혹여나 어떤 객체가 여러곳에서 변경이 되더라도 그 결과가 모두에게 동일하게 적용되어야하는 경우엔 Identitycontrol해야하는 상황이 됩니다

즉, reference type의 특징인 instance의 동일성을 보장해야하는 경우엔 class를 사용해야하는겁니다

struct의 경우엔 IdentityControl할 필요가 없는 경우 사용하라고 되어있습니다

value type의 속성처럼 instance의 동일성을 보장하지 않아도 되는 경우에 struct를 사용하면됩니다


reference type의 예측불가능함

그러면 사실 위에 두가지 문단을 보면
제가 처해왔던 상황에 대입해봐도 class를 사용할 필요가 없을거같다는 느낌이 들수도 있습니다

결국 ViewController하나에 ViewModel하나(ViewModel을 공유할 필요가 없음)기때문에 딱히 Identity를 Control할 필요가 없었거든요

하지만 struct안에 class객체가 들어있다면 이야기가 조금 달라집니다

class A {
    deinit {
        print("메모리해제!")
    }
}

struct ViewModel {
    var A = A()
}

이런 ViewModel이 있다고 칩시다
ViewContoller를 push할때마다 각각의 ViewController안에 변수에 ViewModel을 copy해서 넣어준다고 하면 navigation push를 두번하고 pop을 두번하면 class A의 deinit이 몇번 호출될까요?

pop될때마다 viewController가 deinit되니까 viewModel구조체가 stack에서 사라질거고 그러면 당연히 viewModel안에있는 class도 deinit되니까 deinit이 두번 호출된다라고 생각하실수도 있지만 실제로는 마지막 pop을 했을때 한번만 deinit이 됩니다

우리가 struct안에 value type만 있으면, viewModel을 공유할 필요가 없어서 identity를 control할 필요가 없다면 정말로 viewModel을 struct로 만들어도 괜찮다고 생각합니다

하지만 제 프로젝트의 경우엔 api를 호출하는 객체를 class로 만들어서 viewModel이 가지고 있어야하는데 이런경우엔 struct로 viewModel을 만든다면 제가 모르는 어떤 effect가 발생할지 모릅니다

이 말은 무슨 문제가 생기더라도 파악하기가 어려워진다는 뜻이기도 합니다

또 한가지 생각해봐야할 부분은 프로젝트의 규모가 커지게되면 분명히 ViewController가 다르더라도 공유해야할 로직이 생길수도있고 공유해야할 데이터가 생길 수 있게됩니다 다시말해 추후에 IdentityControl해야하는 경우가 발생할 수 있습니다

그래서 결국 프로젝트의 확정성을 고려하면 ViewModel은 class로 구현하는게 조금더 유연함을 고려한 방식이 아닐까라는 생각을 하게되었습니다


당연히 반대하시는 분들도 계실수있습니다
나름대로 고민을 하고 적은 글이긴 하지만 언제든지 반대하시는 이유를 댓글로 달아주신다면 감사하겠습니다

포스팅을 작성하면서

ViewModel을 class로 할지 struct로 할지는 단순하게 결정할 문제라기 보다는 설계단계에서 정해놓고 가야하는 주제가 아닌가라는 생각이 들었습니다

우리가 instance의 동일성을 고려해야할 기능이 있는지 추후에 그런 기능이 추가될 가능성이 있는지를 판단하고 선택해야한다는 나름의 결론에 도달하게 된것같습니다

아마 딱 정답이 있는 주제는 아니라고 생각이 듭니다
제가 적었던 그런 부분도 A라는 해결방법이 있고 그 방법을 사용해서 문제점으로 지적한 부분을 해결한다면 struct로 만들어도 문제가 없을수있겠죠?

하지만 아무런 고민없이 class로 하던데?라는 이유로 ViewModel을 class로 만드는 것보다는 틀리더라도 제 나름대로의 이유를 확립하고 사용하는것이 나중에 다른 의견을 마주하게 되더라도 잘 수용할 수 있는 기반이 될거라는 생각이 들어서 이렇게 주저리주저리 글을 적었습니다

오늘 이야기는 여기까지 하도록 하겠습니다
그럼20000!

profile
AppleDeveloperAcademy@POSTECH 1기 수료, SOPT 32기 iOS파트 수료

3개의 댓글

comment-user-thumbnail
2024년 3월 16일

좋은 글 감사합니다

1개의 답글
comment-user-thumbnail
2024년 4월 24일

좋은 글 감사합니다 :)

답글 달기