본문 바로가기
이모저모/UIKit

싱글톤 앨범 이미지 서비스 만들기 with Rx or Combine

by ARpple 2023. 11. 28.

#1. PHPickerViewController 다루기

PHPickerViewController를 이용해서 여러 앨범 내부 이미지의 이미지 고유 ID를 가져오기

기본 구조

import Foundation
import Photos
import PhotosUI
import Combine
import UIKit
final class PhotoService{
    static let shared = PhotoService()
    var passthroughIdentifiers = PassthroughSubject<([String],UIViewController),Never>()
// RxSwift 사용 시...
//  var passthroughIdentifiers:PublishSubject<([String],UIViewController)> = .init()
    private weak var viewController: UIViewController?
    static let limitedNumber = 10
    private init(){}
...
✅ PHPicker 화면을 띄워주는 viewController를 약한 참조로 사용한다.
✅ passthroughIdentifiers 이미지 아이디와 화면을 띄우는 viewController의 값을 가져온다. ⇒ present한 컨트롤러만 이 Subject에 반응하기 위함..!

PHPicker Present 메서드

...
func presentPicker(vc: UIViewController,multipleSelection: Bool = false,prevIdentifiers:[String]? = nil) {
        self.viewController = vc
        let filter = PHPickerFilter.images
        var configuration = PHPickerConfiguration(photoLibrary: .shared())
        configuration.filter = filter
        configuration.preferredAssetRepresentationMode = .automatic
        configuration.selection = .ordered
        configuration.selectionLimit = multipleSelection ? Self.limitedNumber : 1
        if let prevIdentifiers{
            configuration.preselectedAssetIdentifiers = prevIdentifiers
        }
        let picker = PHPickerViewController(configuration: configuration)
        picker.delegate = self
        viewController?.present(picker, animated: true)
    }
...

PHPicker 이미지 추가 메서드

extension PhotoService: PHPickerViewControllerDelegate{
    // 델리게이트 구현 사항
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        viewController?.dismiss(animated: true)
        let identifiers = results.map(\.assetIdentifier!) // 이미지에 존재하는 identifier만 가져온다.
        guard let viewController else {return}
        passthroughIdentifiers.send((identifiers,viewController))
//        rxSwift를 사용하는 경우...
//                passthroughIdentifiers.onNext((identifiers,viewController)) 
    }
}

위 구현한 서비스 사용 예시

이미지 가져오는 영역

final class AddSetVM{
...
func bindPhPicker() {
        photoService.passthroughIdentifiers.sink {[weak self] val,vc in
            guard let self,self.vc == vc,let newAlbumID = val.first else {return}

            let newFileName = newAlbumID.getLocalPathName(type: .photo)
            let prevFileName = self.setItem?.imagePath
            self.setItem?.imagePath = newFileName
            Task{@MainActor [weak self] in
                guard let self else {return}
                if !self.ircSnapshot.existItem(id: newFileName){
                    await ImageService.shared.saveToDocumentBy(photoIDs:[newAlbumID])
                }
                if let setItem{ updatedSetItem.send((setItem,true)) }
                Task.detached {
                    await self.ircSnapshotUpdate(new: newFileName, prev: prevFileName)
                }
            }
        }.store(in: &subscription)
    }
...
}

PHPicker 띄우기

final class AddSetVC{
...
    func present(){
        photoService.presentPicker(vc: self,multipleSelection: false)
    }
}

전체 코드

PhotoService_.swift
0.00MB

 

댓글