.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
를 구현했다.
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을 만들었다.
// 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이긴 하지만 내 일지니까 그냥 쓰자면 🤣
이 앱을 배포했던 개발자 계정이 끝난 것 같다.
애플 로그인이 안 돼서 서버측에서 고쳐주는 중... 🔨
그동안은 사실 개발자 계정 있으면 내주세요!
하고 개인 계정으로 잘 냈었는데, 이번 사태를 겪고 나니 회사(는 당연히 회사 계정이겠지만), 팀 계정으로 배포를 최대한 해야 할 것 같다.