실수

의도치않은 ObservedObject 객체 초기화 실수

elisha0103 2022. 11. 7. 00:04

SwiftUI에서 관찰중인 객체의 변경에 반응해서 화면을 업데이트해서 보여줄 때 쓰는 것이

바로 StateObject, ObservedObject, EnvironmentObject 이 세가지 이다.

 

이런 생각을 해본 적이 있다.

 

'StateObject, ObservedObject, EnvironmentObject 이 모두를 동시에 사용할 수 있을까?'

 

우리 팀에서 만든 토이프로젝트에서 위 세가지 모두를 동시에 사용했는데,이로서 나타난 나의 실수를 기술하고자 한다.

 

우리가 만든 토이프로젝트의 간단 예를 설명해주자면,1. 통아저씨 게임2. 돌림판 게임3. 계산기이 세가지가 모두 포함된 어플이다.여기서 위 세가지 기능의 모든 결과를 @EnvironmentObject resultData 에 넣어줘야한다.

 

하지만 계산기에서 계산을 수행되는데 필요한 연산 함수, 데이터는@ObservedObject calculatorData 변수에서 계산, 저장이 된다.

 

계산기 뷰에서 선언된 변수

이렇게 선언해도, 나는 계산기가 정상적으로 잘 작동될 것이라 판단했다.

@ObservedObject 계산기

하지만 위와 같이, 계산 '=' 버튼을 누르면 계산 결과를 보여주는 것이 아닌,

0만 보여준다는 것이다.

계산 결과 기록

계산 기록은 잘 넘어가지만, 왜 계산을 하면 바로 0으로 초기화되는지 알 수 없었다.

 

그렇게 구글링을 하고 알아보던 중,

내가 선언한 @ObservedObject가 문제라는 것을 알게 됐다.

 

@State, @ObservedObject, @EnvironmentObject의 특성을 다시 이해하게 됐다.

'관찰중인 객체의 변경에 반응하여 View를 업데이트 해준다.'

 

여기서 ObservedObject와 EnvironmentObject 모두 관찰 객체가 변경된다면

업데이트 해주는 View는 계산기 뷰일 것이다.

 

즉, ObservedObject 객체가 변경되면 계산기 뷰가 업데이트되고

EnvironmentObject가 변경되면 마찬가지로 계산기 뷰가 업데이트된다.

 

계산 결과가 EnvironmentObject 변수에 넘어가 최신화가 된다면, 계산기 뷰는 초기화가 된다.

그렇게 되면 자연스래 ObservedObject의 변수도 초기화가 된다.

계산기에서만 사용되는 ObservedObject 변수가 초기화가 되면서 

계산결과는 사용자에게 보여지지 않고, 기록만 된 후 바로 초기 값 '0'으로 변경되는 것이다.

 

상태변수 프로퍼티에 대해 제대로 알고 있었다면 위와 같은 실수를 하지 않았을 터,,

그렇다면 상태 변수 프로퍼티를 동시에 사용했을 때, 서로 영향받지 않게 사용할 방법이 있을지 고민해봤다.

 

그렇기에 나온 것이 바로 @StateObject였다.

 


@StateObject는 겉보기에 ObservedObject와 비슷하게 동작한다.

ObservableObject 프로토콜을 따르는 것도 같다.

 

@StateObject는 해당 객체가 포함되어있는 뷰가 변경되어도 @StateObject는 영향을 받지 않는다.

무슨말이냐면, @ObservedObjet가 포함되어 있는 뷰가 어떤 영향에 의해서 최신화가 된다면

@ObservedObject 객체도 다시 처음상태나 어떤 기준의 시점으로 돌아갈 것이다.

하지만 @StateObject는 다른 영향에 의해서 뷰가 최신화 된다 하더라도 값이 변경되지 않는다.

 

따라서 화면이 다른 영향에 의해서 다시 그려질 가능성이 있는 경우, 안전하게 @StateObject로 선언하는 것이 좋고,

외부에 의해서 @ObservedObject 객체가 전달되는 경우에는 @ObservedObject로 객체 선언하는 것이 좋다.

 

모든 경우를 @StateObject로 객체를 선언한다면 객체의 라이프 사이클을 복잡하게 할 것이다.

 

@StateObject를 사용하여 계산기를 수정한 결과이다.

개선된 계산기