SwiftUI 팀 프로젝트 혼자 리팩토링하기 #7 : PhotoPicker 로직

·2024년 7월 15일
0

리팩토링 일지

목록 보기
8/13

요약

  • photoPicker 로직 리팩토링

프로젝트 살펴 보기



photoPicker 로직 리팩토링

<리팩토링 전>

View

        .onChange(of: selectedPhoto) { _, newValue in
            PHPhotoLibrary.requestAuthorization { status in
                guard status == .authorized else { return }
                Task {
                    if let data = try? await newValue?.loadTransferable(type: Data.self) {
                        viewModel.selectedImageData = data
                    }
                }
            }
        }

PhotoPicker에서 선택한 이미지를 사용하여 data로 변환하는 작업이 view에서 실시된다.
(특히 photoPicker가 필요한 모든 곳에서 이 코드가 존재한다...!)


<리팩토링 후>

이미지를 선택하여 서버에 보내야 할 때도 그렇고,
프로필 이미지뿐만 아니라 여러 곳에서 photo picker에서 선택한 이미지를 data화한다.

따라서 이를 viewModel과 명확하게 분리하고, 재사용성을 높이기 위해 PhotoUseCase 를 구현했다.


UseCase

protocol PhotoUseCaseType {
    func loadTransferable(_ item: PhotosPickerItem?) -> AnyPublisher<Data, PhotoPickerError>
}

final class PhotoUseCase: PhotoUseCaseType {

    func loadTransferable(_ item: PhotosPickerItem?) -> AnyPublisher<Data, PhotoPickerError> {
        Future<Data, PhotoPickerError> { promise in
            guard let item = item else { return }
            
            item.loadTransferable(type: Data.self) { result in
                switch result {
                case let .success(data):
                    if let data = data {
                        promise(.success(data))
                    } else {
                        promise(.failure(PhotoPickerError.invalid))
                    }
                    return
                case .failure(_):
                    promise(.failure(PhotoPickerError.importFaild))
                }
            }
        }
        .eraseToAnyPublisher()
    }
}

데이터로 변환해야 하는 photoPickerItem을 파라미터로 받고, 성공과 실패로 분리하여 Future로 Publisher을 만들었다.


ViewModel

// View
.photosPicker(isPresented: $viewModel.isPhotoPickerShowed, selection: $viewModel.selectedImage)

view에서 우선 photoPicker에서 선택된 selectedImage 와 바인딩해 줬다.


// ViewModel
    /// 이미지
    @Published var selectedImage: PhotosPickerItem? = nil {
        didSet {
            send(.loadTransferable(selectedImage))
        }
    }
    @Published var selectedImageData: Data?
    @Published var isProfileSheetShowed: Bool = false
    @Published var isPhotoPickerShowed: Bool = false

selectedImage에서는 didSet 으로 값이 변한 직후에 데이터 변경을 요청하는 이벤트를 보낸다.


    func send(_ action: Action) {
        switch action {
        case let .loadTransferable(item):
            photoUseCase.loadTransferable(item)
                .receive(on: DispatchQueue.main)
                .sink { _ in
                } receiveValue: { [weak self] data in
                    self?.selectedImageData = data
                }
                .store(in: &cancellables)

loadTransferable action 요청 시, photoUseCase에 접근한다.
data화된 값을 받으면 selectedImageData에 저장하여,
아래와 같이 View에서 이미지로 보여줄 수 있도록 했다.

            if let data = viewModel.selectedImageData,
                let image = UIImage(data: data) {
                Button {
                    viewModel.send(.presentProfileModifySheet)
                } label: {
                    Image(uiImage: image)
                        .resizable()
                        .frame(width: 130, height: 130)
                        .clipShape(Circle())
                }

photoUseCase는 마이페이지나, 게시글 작성 시 이미지 등록처럼 여러 곳에서 재사용될 수 있을 것 같다!



tmi이긴 하지만 내 일지니까 그냥 쓰자면 🤣
이 앱을 배포했던 개발자 계정이 끝난 것 같다.
애플 로그인이 안 돼서 서버측에서 고쳐주는 중... 🔨

그동안은 사실 개발자 계정 있으면 내주세요!
하고 개인 계정으로 잘 냈었는데, 이번 사태를 겪고 나니 회사(는 당연히 회사 계정이겠지만), 팀 계정으로 배포를 최대한 해야 할 것 같다.

0개의 댓글

관련 채용 정보