# __[iOS] SwiftUI 채팅화면 MainTread 락현상 수정하기__ 안녕하세요 __물먹고하자__ 입니다 :) 미뤄왔던 업무중에 SwiftUI쪽 채팅화면이 어느순간부터 느려지고 있어서 개선하고자 합니다. 예전에 작성했던 글 : [[SwiftUI 공부] 그룹웨어 채팅 Objc -> Swift, SiwftUI 적용기](https://xodhks0113.blogspot.com/2022/07/swiftui-objc-swift-siwftui.html) 2022년도에 변경하고, 최적화는 추가적으로 진행하지 못했었네요 ㅠㅠ __일단 바로 시작!__ --- ## 1. __원인을 찾아보자__ > 💡수정전.gif 부분에서 스크롤시 __MainThread 락현상이 보임.__ 원인을 찾아보자! --- ## 2. 말풍선에 사용되는View를 기본 Text 바꿔보자 > 💡 기존에 말풍선 부분을 Text(임시)로 변경시 __MainThread 락현상이 보이지 않았음.__ - API 통신부분에 의해 느려지는건 아님. - ScrollView + LazyVStack에 문제가 있는게 아님. - __말풍선영역에 대한 문제가 있어 보임. (여기다!!)__ --- ## 3. 말풍선을 그릴때 어떤 문제인지 확인해보기 말풍선 부분을 직전 2022년도에 작업을 진행할때 View를 나눠서(정리)개발을 하였는데, 각각의 __View를 EnvironmentObject__로 사용하여 개발을 했었다. 당시에는 __EnvironmentObject__ 몰라서 사용했었는데, 채팅 특성상 해당화면을 다른곳에서 쓸일이 없더라구요. __StateObject__나 아니면 __ViewBuilder__ 함수화 해서 사용해도 상관없을 화면들로 판단되었습니다. 3개다 사용해도 문제가 없는데, 메모리 이슈라고 판단 이들어 ChatGPT 궁금증 문의! > 💡 ChatGPT 검색후 도움건 __(EnvironmentObject 관련 검색)__ - Observed Updates: EnvironmentObject는 데이터가 변경될 때마다 뷰가 다시 그려지게 하는데, __여러 개의 객체가 동시에 업데이트되면 UI 스레드에서의 부하가 증가해 렌더링 속도가 느려질 수 있습니다.__ - Dependency Chains: EnvironmentObject가 중첩되거나 서로 참조하는 경우, 그 의존 관계가 복잡해져서 일부 업데이트가 불필요하게 발생할 수 있습니다. 이로 인해 __불필요한 리렌더링이 발생하면서 성능에 영향을 줄 수 있습니다.__ - 메모리 사용: EnvironmentObject 자체가 메모리를 크게 차지하지는 않지만, 그 안에 저장된 데이터의 크기와 해당 데이터를 __참조하는 뷰 계층의 깊이에 따라 메모리 사용이 증가할 수 있습니다.__ 특히, 상태가 여러 뷰에서 참조될 경우 시스템이 관리하는 상태의 수가 늘어나면서 메모리 관리 효율이 떨어질 수 있습니다. __음... 제 얘기하는줄... 계층으로 값 전달하고 있었다..__ 말풍선 화면을 그릴때 __ScrollView + LazyVStack 에서 itemList[item]__을 ㄴ 1) 껍데기View __environmentObject(item) 전달__ --ㄴ 2) 껍데기View에서 타입별 말풍선화면 구분 각각의 말풍선에 __environmentObject(item) 전달__ ----ㄴ 3) 각각의 말풍선 중에 또 답글이거나, 다른 특수한 상황일때 __environmentObject(item) 전달__ 거기에 __Published__ itemList 여서 자동갱신시점이 더 많을 수 밖에 없는 환경 추가로 EnvironmentObject을 StateObject 로 변경할껀데 대응이 맞는지 검색해보기 > 💡StateObject, ObservedObject 관련 검색! - __StateObject__ * 용도: 해당 객체의 소유자가 되고, 초기화와 생명주기를 관리할 때 사용합니다. * 상황: 최상위 뷰나 해당 객체를 처음 생성하는 뷰에 사용합니다. * 생명주기: @StateObject로 선언된 객체는 뷰가 다시 그려지더라도 한 번만 생성되며, 뷰가 메모리에서 사라질 때 해제됩니다. - __ObservedObject__ * 용도: 객체를 소유하지 않고, 이미 외부에서 소유하고 있는 객체에 의존할 때 사용합니다. * 상황: __상위 뷰에서 생성된 객체를 하위 뷰에서 구독__할 때 사용합니다. * 생명주기: @ObservedObject는 객체를 생성하거나 관리하지 않으므로, 뷰가 다시 그려질 때마다 새롭게 할당되지 않습니다. 단순히 상위 뷰로부터 전달된 객체의 변경을 반영할 뿐입니다. 그렇다면 제 상황에서는 사실 객체를 전달할 필요까지는 없어서 __EnvironmentObject__를 __ViewBuilder__로 내부 뷰 함수로 만들고, 어쩔수 없는경우에는 __ObservedObject__로 변환 하여 사용해야겠다는 판단이 드네요! >💡 작업후... __EnvironmentObject__을 사용했을때 보다는 조금 나아진정도? 드라마틱한 효과로 보이진 않았다 ㅠㅠ --- ## 4. 그렇다면.. 말풍선을 만드는 객체가? 문제가 있나 >💡위에까지 실험 후 말풍선을 그릴때 __Text영역(Attribute정보)__를 그려주기 위한 설정값(Option)을 만다는 부분을 시간을 체크 - 설정값(Option)을 생성하는 행위가 __각각 0.3밀리초 만큼 걸리는 현상을 확인__ 각각의 말풍선마다 __멘션, Custom링크들 처리__들이 있어서 Text 표현시 __AttributeString__ 처리하고 있습니다. 위의 이미지는 해당 함수부분 문제로 생각되는 부분은 함수 내부의 __왼쪽, 오른쪽 말풍선에 따른 각각의 색상처리를 하기위한 Option객체!!__ 생각해보면 저 __Option객체가 왼쪽1개, 오른쪽1개__ 거의 고정이였는데, 왜 텍스트 값 뽑을때마다 생성했는지 모르겠내요 ㅠㅠ (실수) [[Swift 공부] 구조체 vs 클래스 (Struct vs Class)](https://xodhks0113.blogspot.com/2019/09/swift-vs-struct-vs-class.html) 예전에 객체 생성실험도 했었네요 기능상으론 동일하지만, __생성부분을 1번만 전역으로 참조__해서 쓰는형식으로 수정결정! 수정 전 속도체크하면 __빨간네모참고__ Option 객체 생성시마다 0.021초씩 누적되는 현상 확인 수정 후 호출되는 위치는 같지만, 생성을하지 않다보니 __여러번 호출되도 시간초가 차이가 나지 않음.__ --- ## __마무리__ 앞서 SwiftUI로 채팅부분을 만들때 SwiftUI를 처음 도입하기도 했고, 지식을 많이 얻지 못한상태에서 개발했었는데 나쁘지 않았던 결과였습니다. 하지만 역시나 딱히 __코드개선없이 기능만 추가되다보니 어느순간 관리가 제대로 되지 않고 있었네요.__ 그래도 뒤늦게 나마 사용성 문제가 되는 부분을 고쳐서 다행이라고 생각하네요. 추가로 개선을 하면서 __ScrollView + LazyVStack의 이슈건 Offset 이동이 불가능한 부분__으로 인하여(자연스러운 스크롤 고정효과가 안됨) 최근에 __iOS16 이상 UICollectionView + SwiftUI 버전__으로도 추가 개선중입니다. 이부분은 작업 완료되면 공유드리겠습니다. 오늘은 이만! 즐거운 코딩되세요~ 끝.
댓글
댓글 쓰기