사용하려는 기기에 있는 사진을 가져와서 보여주려고 하니, UIImagePickerController 에 대한 정보가 많았습니다.
글을 읽다보니 PHPickerViewController 에 대한 정보를 보았고, 해당 클래스로 코드를 변경하게 되었습니다.
UIImagePickerController (링크)
사진을 찍고, 동영상을 녹화하고, 사용자의 미디어 라이브러리에서 항목을 선택하기 위한 시스템 인터페이스를 관리하는 보기 컨트롤러
PHPickerViewController (링크)
사진 라이브러리에서 자산을 선택하기 위한 사용자 인터페이스를 제공하는 보기 컨트롤러
iOS 14 이상에서 지원
우선 왜 바꾸어야 했는지 ?
UIImagePickerController 에서 phAsset 으로 정보를 가져올 수 있었으나, 공식문서에서도 PHPickerViewController를 사용하도록 합니다.
📌 The PHPickerViewController class is an alternative to UIImagePickerController.
PHPickerViewController improves stability and reliability, and includes several benefits to developers and users
📌 User-selectable assets that aren’t available for UIImagePickerController
공식 문서에서 PHPickerViewController 보게 되면 내용이 적혀있습니다.
구현하고자 하는 것이 assets 중에서 location, creationDate가 필요하기 때문에 사용하였습니다.
무엇이 바뀌었지 ?
기존에는 권한 요청으로 모든 앨범 접근에 대한 설정을 하였으나 개인정보 보호 이슈로 인해서 생겨난(?) PHPickerViewController는 특정 사진 혹은 모든 사진에 권한 요청을 해당 기능을 사용할 때 팝업을 띄워서 관리를 해줍니다.
RAW 및 파노라마 이미지와 같은 크고 복잡한 자산을 안정적으로 처리, UIImagePickerController 에서 사용할 수 없는 사용자 선택 가능 자산, 유효하지 않은 입력에 대한 엄격한 검증 등이 있습니다.
PHPickerViewController는 UIImagePickerController에서 썼던 카메라 사용과 사진을 편집하는 기능을 제공하지 않습니다.
코드로 어떻게 동작을 하는지 ?
import UIKit
import PhotosUI
class ViewController: UIViewController {
var imageView = UIImageView(frame: CGRect(x: 90, y: 110, width: UIScreen.main.bounds.size.width - 180, height: UIScreen.main.bounds.size.width - 180))
override func viewDidLoad() {
super.viewDidLoad()
imageView.backgroundColor = .lightGray
self.view.addSubview(imageView)
let leftButton = ButtonModels().addSymbolButton(systemName: "plus", posX: 20, posY: 60)
leftButton.addTarget(self, action: #selector(phpicker), for: .touchUpInside)
self.view.addSubview(leftButton)
}
@objc func phpicker() {
var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
configuration.selectionLimit = 1
configuration.filter = .images
let picker = PHPickerViewController(configuration: configuration)
picker.delegate = self
self.present(picker, animated: true, completion: nil)
}
}
extension ViewController: PHPickerViewControllerDelegate {
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true, completion: nil)
guard !results.isEmpty else { self.dismiss(animated: true, completion: nil); return }
if results[0].itemProvider.canLoadObject(ofClass: UIImage.self) {
results[0].itemProvider.loadObject(ofClass: UIImage.self) { image, error in
if let error = error {
print(error)
return
} else {
DispatchQueue.main.async {
self.imageView.image = image as? UIImage
}
}
}
}
}
}
정보를 어떻게 얻는지 ?
import UIKit
import PhotosUI
class ViewController: UIViewController {
var imageView = UIImageView(frame: CGRect(x: 90, y: 110, width: UIScreen.main.bounds.size.width - 180, height: UIScreen.main.bounds.size.width - 180))
override func viewDidLoad() {
super.viewDidLoad()
imageView.backgroundColor = .lightGray
self.view.addSubview(imageView)
let leftButton = ButtonModels().addSymbolButton(systemName: "plus", posX: 20, posY: 60)
leftButton.addTarget(self, action: #selector(phpicker), for: .touchUpInside)
self.view.addSubview(leftButton)
}
@objc func phpicker() {
var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
configuration.selectionLimit = 1
configuration.filter = .images
let picker = PHPickerViewController(configuration: configuration)
picker.delegate = self
self.present(picker, animated: true, completion: nil)
}
}
extension ViewController: PHPickerViewControllerDelegate {
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true, completion: nil)
guard !results.isEmpty else { self.dismiss(animated: true, completion: nil); return }
// 이미지 정보 가져오기
if let assetId = results[0].assetIdentifier {
let assetResults = PHAsset.fetchAssets(withLocalIdentifiers: [assetId], options: nil)
print(assetResults.firstObject?.creationDate ?? "만든 날짜를 모르겠습니다")
if let coordinate = assetResults.firstObject?.location?.coordinate {
print(coordinate)
} else {
print("여기가 어딘지 모르겠습니다")
}
print(assetId)
}
if results[0].itemProvider.canLoadObject(ofClass: UIImage.self) {
results[0].itemProvider.loadObject(ofClass: UIImage.self) { image, error in
if let error = error {
print(error)
return
} else {
DispatchQueue.main.async {
self.imageView.image = image as? UIImage
}
}
}
}
}
}
PHAsset 정보를 가져오는 코드
let assetId = results[0].assetIdentifier
let assetResults = PHAsset.fetchAssets(withLocalIdentifiers: [assetId], options: nil)
// 만들어진 날짜
assetResults.firstObject?.creationDate
// 장소 정보
assetResults.firstObject?.location?.coordinate
🚨 Error 발생 🚨
2022-11-24 20:29:34.994896+0900 PHpickerSample[76462:5118295] [access] This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSPhotoLibraryUsageDescription key with a string value explaining to the user how the app uses this data.
CoreSimulator 857.7 - Device: iPhone 14 Pro (34B54DD5-4D02-498F-A7D5-8EE84F95D675) - Runtime: iOS 16.0 (20A360) - DeviceType: iPhone 14 Pro
📌 해결
권한 부여를 하지 않아서 발생하였기 때문에 생긴 거였다.
'Language > Swift' 카테고리의 다른 글
[Swift] Firebase database 설명, 선택 그리고 설정 (0) | 2022.12.06 |
---|---|
[Swift] set size and position for view(CGRect, AutoLayout) (0) | 2022.12.01 |
[Swift] Firebase Storage Xcode에 설치하기 (2) | 2022.10.15 |
[swift] Pod? Cocoapod install & remove (0) | 2022.10.05 |
[SwiftUI] Naver Map 처음 위치, 현재 위치, Maker (0) | 2022.09.26 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!