[iOS] 앨범에서 사진 선택하기(2) - PHPickerController

Madeline👩🏻‍💻·2024년 2월 20일
1

iOS study

목록 보기
37/61

💐

이전 글:
https://velog.io/@maddie/iOS-%EC%95%A8%EB%B2%94%EC%97%90%EC%84%9C-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%84%A0%ED%83%9D%ED%95%98%EA%B8%B0-ImagePicker-PHPickerController
에서 이어집니다!

ImagePicker의 변천사

이미지 선택 기능을 구현하기 위해 iOS 개발자들은 주로 UIImagePickerController를 사용해 왔다. 그러나 iOS 14 이후, Apple은 새로운 PHPickerViewController를 도입했다. 이 변화는 사용자의 프라이버시 보호를 강화하고 더 나은 사용자 경험을 제공하기 위한 목적에서 비롯되었다. 또한, YPImagePicker와 같은 타사 라이브러리를 사용하여 인스타그램과 같은 UI를 쉽게 구현할 수 있다.

이전 글에서는 iOS 14 이전에 사용하던 ImagePicker에 대해 알아보았다.
ImagePicker을 사용해서 이미지뷰에 띄우는 작업까지 수행했는데, 실제 앱에서는 이를 데이터베이스에 저장하는 것이 중요하다. 예를 들어 Realm 데이터베이스에 데이터를 저장하고, 앱 Sandbox내에 Document 폴더에 실제 이미지를 저장하는 작업이 필요하다.

이 작업은 따로 다른 글에 정리해두도록 하겠다.

PHPickerController

아무튼, iOS 14버전 이후에는 PHPickerController를 사용하도록 되어있는데, 뭐가 달라졌나?

여러 장을 선택할 수 있다.

원래는 별도의 기능 구현이 필요했는데, PHPickerController는 이 기능을 기본적으로 제공한다.

https://developer.apple.com/documentation/photokit/phpickerviewcontroller

https://developer.apple.com/videos/play/wwdc2022/10023/

공식문서를 보면 여러 장을 선택할 수 있는 기능 외에도, 라이브 포토만 선택할 수 있다던지, 지연된 이미지 로딩 및 복구하는 UI라던지 하는 기능이 추가되었다.

사용해보자

실습

// MARK: PHPickerController
        var configuration = PHPickerConfiguration()
        configuration.selectionLimit = 3
        // 영상, 사진 분리
        configuration.filter = .images
        // configuration.filter = .any(of: [.videos, .images]) // 여러 종류 필터
        let picker = PHPickerViewController(configuration: configuration)
        
        picker.delegate = self
        
        
        present(picker, animated: true)

요렇게 PHPickerController를 선언해주고,
다른 기능들과 동일하게 delegate 프로토콜을 채택해준다.

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        
        let itemProvider = results.first?.itemProvider
        
        // 옵셔널 해제 & 이미지 가져올 수 있는지
        if let itemProvider = itemProvider, itemProvider.canLoadObject(ofClass: UIImage.self) {
            itemProvider.loadObject(ofClass: UIImage.self) { image, error in
                self.photoImageView.image = image as? UIImage
            }
        }
        
        picker.dismiss(animated: true)
    }

자 이 상태로 돌려보면,
무시무시한 보라색 에러가 뜬다.
👿
UIImageView.image must be used from main thread only

하여튼 보라색 에러는 다 메인스레드에서 하라는 뜻인것같다.
이미지를 가져오는 건 비동기로 이루어지기 때문에, UI업데이트는 메인스레드에서 처리해줘야된다.

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        
        let itemProvider = results.first?.itemProvider
        
        // 옵셔널 해제 & 이미지 가져올 수 있는지
        if let itemProvider = itemProvider, itemProvider.canLoadObject(ofClass: UIImage.self) {
            itemProvider.loadObject(ofClass: UIImage.self) { image, error in
                DispatchQueue.main.async {
                    self.photoImageView.image = image as? UIImage
                }
            }
        }
        
        picker.dismiss(animated: true)
    }

요렇게 하면 동작을 잘 한다!
근데 이것도 왜 권한 없이 가능한가?
이것도 마찬가지로 Out of Process
갤러리에 있는 사진을 가져오는 것! 이미지 데이터만 가져오는 건 권한 없이 가능하다.

그래서 이미지 데이터 외에 다른 데이터를 가져오면,

override func viewDidLoad() {
        super.viewDidLoad()
        
        // MARK: PHAsset - 사진, 시간, 위치
        PHAsset.fetchAssets(with: nil)


에러가 뜬다.
이제는 진짜 권한을 받아야 한다.

info.plist


Privacy - Photo Library Usage Description

Privacy - Camera Usage Description

요렇게 두 개 허용해주면,

업로드중..

이렇게 허용 권한이 뜨고, 그리고 나머지 기능도 가능해진다.

profile
🍎 Apple Developer Academy@POSTECH 2기, 🍀 SeSAC iOS 4기

0개의 댓글