점검
- C2 데드라인인 23일 수요일을 하루 남겨놓고 있다.
- 오늘은 학습 내용과 구현 내용을 점검하는 마일스톤이었다. 그룹 멘토들과 함께 작업물과 코드를 리뷰했다.
- 루미의 피드백
- View에서 ObservableObject 등을 private으로 잡고 init을 직접 구현하는 습관에 대한 물음
- 구조체를 정의할 때 생성자가 있는 건 부자연스럽다. 생성자에서 특정 로직이 수행된다는지 이유가 있어야 한다.
- 꼭 뷰모델이 private이어야 하는가?
- 뷰모델, DI 컨테이너 등 단일 책임에 맞게 나누어보기
- 한 객체에서 구현이 너무 긴 경우 Extension을 통해 관계 있는 로직끼리 묶어 구현해볼 수도 있다.
- View에서 ObservableObject 등을 private으로 잡고 init을 직접 구현하는 습관에 대한 물음
- 곰민의 피드백
- C2 기본 목표였던 CRUD 이상의 부분이 개인적인 목표였던 것 같은데 여기에 대해서도 발표에서 소개해줄 수 있으면 좋겠다.
로딩
- 이런 식으로 로딩 화면을 구현했다.
- 뷰
FetchResultView .task(isLoading: $isLoading) { await viewModel.taskDidStart() } .loading(isLoading: isLoading)
- 각 모디파이어는 이렇다
import SwiftUI struct LoadingViewModifier: ViewModifier { var isLoading: Bool func body(content: Content) -> some View { if isLoading { // -> 과연 괜찮을까? ZStack { ProgressView() content } } else { content } } } extension View { public func loading(isLoading: Bool) -> some View { modifier(LoadingViewModifier(isLoading: isLoading)) } }
import SwiftUI struct TaskWithLoadingModifier: ViewModifier { var isLoading: Binding<Bool> var task: () async -> Void func body(content: Content) -> some View { content.task { isLoading.wrappedValue = true await task() isLoading.wrappedValue = false } } } extension View { public func task(isLoading: Binding<Bool>, task: @escaping () async -> Void) -> some View { modifier(TaskWithLoadingModifier(isLoading: isLoading, task: task)) } }
- 뷰
- task에 넘긴 클로져가 무한으로 호출되는 문제가 발생했다. onAppear도 마찬가지 였다.
- isLoading이 변경되므로 리렌더링되는 건 맞지만 리렌더링된다고 호출되는 것은 이상하다. 레퍼런스를 보면 둘 다 Appear를 통해 트리거되는 것으로 나와있다.
- 결론은 LoadingViewModifier 문제였다. isLoading에 의해 뷰 구조가 변경되는데 이게 onAppear 호출을 일으키는 것 같다. 내일 멘토분들한테 물어봐야겠다.
struct LoadingViewModifier: ViewModifier { var isLoading: Bool func body(content: Content) -> some View { /* 이전 if isLoading { ZStack { ProgressView() content } } else { content } */ // 변경 후 ZStack { if isLoading { ProgressView() } else { Color.clear } content } } } extension View { public func loading(isLoading: Bool) -> some View { modifier(LoadingViewModifier(isLoading: isLoading)) } }