제가 만드는 프로젝트에서 사용자에게 기기의 사진권한을 받아야 얼굴사진을 받아올 수 있기에 사진권한 기능을 추가하였습니다.
extension SignUpPictureViewController: PHPickerViewControllerDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
일단 PHPickerViewControllerDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate 이 세종류의 프로토콜을 채택해야 합니다.
이 프로토콜들은 이미지 피커와 네비게이션 컨트롤러와 관련된 상호작용을 다루기 위한 것입니다.
@objc private func openPhotoLibrary() {
// 포토 라이브러리에 대한 권한이 허용되었는지 확인
if PHPhotoLibrary.authorizationStatus() == .authorized {
// PHPickerViewController 구성
var configuration = PHPickerConfiguration()
configuration.selectionLimit = 3 // 최대 선택 가능한 이미지 수
let picker = PHPickerViewController(configuration: configuration)
picker.delegate = self
// 이미지 선택 뷰컨트롤러 표시
present(picker, animated: true, completion: nil)
} else {
// 권한이 거부된 경우 처리
pictureManager.unauthorized(in: self)
}
}
코드설명
이제 이미지를 선택했을때 처리를 해줘야합니다
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true, completion: nil)
var selectedImages: [UIImage] = []
for result in results where result.itemProvider.canLoadObject(ofClass: UIImage.self) {
result.itemProvider.loadObject(ofClass: UIImage.self) { [weak self] (image, _ ) in
guard let self = self else { return }
guard let image = image as? UIImage else { return }
selectedImages.append(image)
guard selectedImages.count == results.count else { return }
userImages = selectedImages
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
collectionView.reloadData()
configNextButton(isEnabled: true)
}
}
}
}
코드설명
이전까지는 뷰컨트롤러에서 사진 델리게이트를 활용하여 사진첩에 간편하게 접근하고 최대 3장의 사진을 선택할 수 있도록 구현했습니다. 이제는 사용자에게 사진 권한을 묻기 위한 알림을 띄우기 위한 코드를 작성해야합니다. 저는 사진권한을 묻기 위한 기능들을 하나의 서비스로 따로빼서 작업하였습니다.
final class PictureService {
func unauthorized(in viewController: UIViewController) {
DispatchQueue.main.async {
viewController.showCustomAlert(alertType: .canCancel, titleText: "사진 라이브러리 권한 필요", messageText: "사진을 선택하려면 사진 라이브러리 권한이 필요합니다. 설정에서 권한을 변경할 수 있습니다.", confirmButtonText: "설정으로 이동", comfrimAction: {
if let settingsURL = URL(string: UIApplication.openSettingsURLString) {
UIApplication.shared.open(settingsURL)
}
})
}
}
코드설명
이제 각 권한 상태에 따른 처리를 위해 switch 문을 사용하여 엑세스 요청을 조건별로 처리해야합니다.
func requestPhotoLibraryAccess(in viewController: UIViewController) {
PHPhotoLibrary.requestAuthorization { [weak self] status in
guard let self = self else { return }
switch status {
case .authorized:
break
case .denied, .restricted, .notDetermined, .limited:
self.unauthorized(in: viewController)
@unknown default:
self.unauthorized(in: viewController)
}
}
}
코드설명
PHPhotoLibrary.requestAuthorization: 이 부분은 Photos 프레임워크에서 권한을 요청하는 메서드입니다. 사용자에게 권한을 요청하고, 결과에 따라 클로저가 호출됩니다.
switch status: status 값을 기반으로 한 switch 문으로, 다양한 권한 상태에 대한 처리를 합니다.
.authorized: 권한이 허용된 상태이므로 별도의 처리 없이 break로 종료합니다.
.denied, .restricted, .notDetermined, .limited: 권한이 거부되었거나, 제한되었거나, 아직 결정되지 않았거나, 제한적인 권한이 있는 경우에는 unauthorized 함수를 호출하여 사용자에게 알림을 표시합니다.
@unknown default: 알 수 없는 다른 상태가 발생한 경우에도 unauthorized 함수를 호출하여 알림을 표시합니다.
현재 구현한 기능에서는 사용자가 사진 접근을 거부하고 설정으로 이동한 후 권한을 변경하면, 다시 앱으로 돌아올 때 네비게이션 스택의 첫 번째 화면으로 이동하는 문제가 발생하고 있습니다. 이 문제는 현재로서는 공식 문서나 다른 출처에서 명확한 해결책을 찾기 어렵습니다. 배달의 민족과 같은 다른 앱에서도 동일한 문제가 발견되어, 이는 애플의 내부 정책에서 비롯된 것으로 보입니다. 현재까지는 이 문제에 대한 공식적인 해결 방법이 알려지지 않았습니다.
해결한 방법