MyPage와 관련된 상위, 하위 뷰를 재활용 가능하게 만들고 프로토콜 지향 패러다임에 맞춰 MyPageViewModel 분리
어떻게 작동하나요? code 기반으로 설명해주세요
MemoListViewModel 라는 프로토콜을 만들어 MyPageViewModel와 OtherUserViewModel에서 채택하여 사용하도록 구현 하였습니다.
//
// MemoListViewModel.swift
// MyMemory
//
// Created by 정정욱 on 2/2/24.
//
import SwiftUI
import _PhotosUI_SwiftUI
import FirebaseAuth
import FirebaseCore
import FirebaseFirestore
protocol MemoListViewModel: ObservableObject {
var memoList: [Memo] { get set }
var selectedFilter: SortedTypeOfMemo { get set }
var isShowingOptions: Bool { get set }
var isCurrentUserLoginState: Bool { get set }
var user: User? { get set }
var currentLocation: CLLocation? { get set }
var lastDocument: QueryDocumentSnapshot? { get set }
func fetchDistanceOfUserAndMemo(myLocation: CLLocationCoordinate2D, memoLocation: Location) -> Double
func sortMemoList(type: SortedTypeOfMemo)
func fetchUserState()
func fetchCurrentUserLoginState() -> Bool
func fetchCurrentUserLocation(returnCompletion: @escaping (CLLocation?) -> Void)
func pagenate(userID: String) async
}
뷰에서 프로토콜 타입으로 넘겨받아 재사용 가능하게 만들었으며 상태에 따라 각각의 뷰 모델을 사용하게 했습니다.
var body: some View {
ZStack(alignment: .top) {
Color.bgColor.edgesIgnoringSafeArea(.top)
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .leading) {
// 로그인 되었다면 로직 실행
if let currentUser = authViewModel.currentUser, let userId = UserDefaults.standard.string(forKey: "userId") {
let isCurrentUser = authViewModel.userSession?.uid == userId
// 상대방 프로필을 표시할 때는 제네릭을 사용하여 OtherUserViewModel을 전달 MyPage를 표시할 때는 MypageViewModel 전달
if fromDetail == true && otherUserViewModel.memoCreator.isCurrentUser == false {
OtherUserTopView(memoCreator: $otherUserViewModel.memoCreator, viewModel: otherUserViewModel)
createHeader(isCurrentUser: isCurrentUser)
ProfileMemoList<OtherUserViewModel>().environmentObject(otherUserViewModel)
} else {
MypageTopView() //
createHeader(isCurrentUser: isCurrentUser)
ProfileMemoList<MypageViewModel>().environmentObject(mypageViewModel)
}
} else {
showLoginPrompt()
}
}
}
}
//이 구조체는 MemoListViewModel 프로토콜을 준수하는 어떤 뷰모델 타입(ViewModel)을 받을 수 있습니다.
struct ProfileMemoList<ViewModel: MemoListViewModel>: View {
@EnvironmentObject var viewModel: ViewModel
@State private var isLoadingFetchMemos = false
var body: some View {
LazyVStack(spacing: 12) {
// 각각의 뷰 모델을 활용하여 메모 리스트를 가져옴
ForEach($viewModel.memoList, id: \.self) { memo in
NavigationLink {
MemoDetailView(memo: memo)
} label: {
ProfileMemoListCell(memo: memo, viewModel: viewModel)
.onAppear {
Task {
// 1. 로그인 되어있는지 체크
// 2. 뷰모델에 따라 알맞은 로직을 실행
if let userId = UserDefaults.standard.string(forKey: "userId") {
if let mypageViewModel = viewModel as? MypageViewModel {
self.isLoadingFetchMemos = true
await mypageViewModel.pagenate(userID: userId)
self.isLoadingFetchMemos = false
} else if let otherUserViewModel = viewModel as? OtherUserViewModel {
self.isLoadingFetchMemos = true
let userId = otherUserViewModel.memoCreator.id?.description
await otherUserViewModel.pagenate(userID: userId ?? "")
self.isLoadingFetchMemos = false
}
}
}
}
}
.buttonStyle(.plain)
}
}
struct ProfileMemoListCell<ViewModel: MemoListViewModel>: View {
@Binding var memo: Memo
@ObservedObject var viewModel: ViewModel
PR 가이드라인
PR Checklist
PR 날릴 때 체크 리스트
PR Type
어떤 종류의 PR인가요?
연관되는 issue 정보를 알려주세요
Issue Number: #160
PR 설명하기
MyPage와 관련된 상위, 하위 뷰를 재활용 가능하게 만들고 프로토콜 지향 패러다임에 맞춰 MyPageViewModel 분리
어떻게 작동하나요? code 기반으로 설명해주세요
MemoListViewModel 라는 프로토콜을 만들어 MyPageViewModel와 OtherUserViewModel에서 채택하여 사용하도록 구현 하였습니다.
뷰에서 프로토콜 타입으로 넘겨받아 재사용 가능하게 만들었으며 상태에 따라 각각의 뷰 모델을 사용하게 했습니다.
가능하다면 추가해주세요
변경 사항 스크린샷 혹은 화면 녹화
폴더, 파일, 클래스, 구조체 이름이 변경되었습니다.
Test 여부
Test 정보
기타 언급해야 할 사항들