IOS

[IOS] PHPhotoLibrary의 requestAuthorizaion 메소드 호출 시 발생할 수 있는 이슈

개인 프로젝트로 photos 프레임워크를 활용하여 사진 관리 애플리케이션을 만들고 있다가 처음 App이 실행됐을때 사용자에게 공유 사진 라이브러리에 대한 권한을 요청하는 과정에서 예상하지 못한 문제가 발생했다. 그 문제에 대해 다뤄보려고 한다.


나는 사진 라이브러리에서 AssetCollection을 fetch하기 위해, 뷰가 로드될 시(viewDidLoad) 사진 라이브러리에 대한 접근과 변경을 관리하는 PHPhotoLibrary 객체의 authorizationStatus 메소드를 사용해서 현재 라이브러리에 대한 권한 상태를 불러왔다.

 

만약 아직 권한이 결정되지 않았다면 PHphotoLibrary 객체의 requestAuthorization 메소드를 호출해서 App이 사진 라이브러리에 접근할 수 있도록 사용자에게 권한을 요청했다. App을 처음 설치하고 시작할 때 한 번만 권한을 요청하고, 그 이후에 실행될때는 승인된 상태일때만 라이브러리에서 데이터를 fetch하도록 했다. 그리고 마지막에 공유 라이브러리의 변경될 때 마다 메시지를 받을 객체로 뷰 컨트롤러를 등록했다.

func checkAuthorization() {
        
        let authorization = PHPhotoLibrary.authorizationStatus(for: .readWrite)
        
        switch authorization {
        case .notDetermined:
            PHPhotoLibrary.requestAuthorization(for: .readWrite) {status in
                switch status {
                case .authorized:
                    print("사용자가 승인함")
                    self.requestCollection()
                    OperationQueue.main.addOperation {
                        self.collectionView.reloadData()
                    }
                case.denied:
                    print("사용자가 거부함")
                default:
                    break
                }
            }
        case .authorized:
            print("승인됨")
            self.requestCollection()
        default:
            print("default")
        }
        PHPhotoLibrary.shared().register(self)

 

그런데 앱을 설치하고 실행해보니 아래와 같은 메시지를 받았다. 뿐만 아니라 사용자에게 권한을 요청하는 메시지가 화면에 보여지기 전까지 에러 메시지가 반복적으로 콘솔에 표시됐고 권한을 줬음에도 데이터가 정상적으로 fetch되지 않았다.

[GatekeeperXPC] Failed to open photo library Error Domain=com.apple.photos.error Code=41011 "Unauthorized access: client does not have valid TCC authorization" UserInfo={NSLocalizedDescription=Unauthorized access: client does not have valid TCC authorization}

 

문제는 마지막 줄의 PHPhotoLibrary.shared().register(self) 때문이었다. 사용자로부터 권한을 얻기 전에 이 메소드가 호출되어 문제가 발생했던 것이다. 나는 당연하게도 연산의 흐름이 사용자가 권한을 결정하고난 후에 checkAuthorization 메소드를 빠져나갈 것이라 판단했었는데, 디버그 모드에서 확인을 해보니 resquestAuthorization 메소드가 호출되자마자 그 결과를 기다리지 않고 바로 checkAuthorization 메소드를 빠져나왔다. 그리고는 viewDidLoad 메소드 안의 다른 작업을 순서대로 실행했다.

 

아마 권한을 요청한 순간부터 다른 스레드가 그 연산을 담당하고, 메인 스레드는 응답을 기다릴 필요 없이 순서대로 다음 작업을 실행하는 것 같다.  그래서 사용자로부터 권한을 승인받은 직후 collectionView.reloadData() 메소드를 호출하면 메인 스레드에서 작업을 수행해야 한다는 경고가 뜬게 아닐까 싶다.

 

결론적으로 위 문제를 해결하려면, PHPhotoLibrary.shared().register(self) 이 메소드를 권한 요청을 담당한 스레드 안에서 호출하면 된다.

 

func checkAuthorization() {
        ...
        
        switch authorization {
        case .notDetermined:
            PHPhotoLibrary.requestAuthorization(for: .readWrite) {status in
                switch status {
                case .authorized:
                    print("사용자가 승인함")
                    self.requestCollection()
                    PHPhotoLibrary.shared().register(self)
                    OperationQueue.main.addOperation {
                        self.collectionView.reloadData()
                    }
         ...

 

참고한 문서

 

When to call PHPhotoLibrary.register in iOS apps

Learn when to call PHPhotoLibrary.register in iOS apps to avoid issues introduced by Apple's PhotoKit framework behavior change in iOS 15.2 and Xcode 13.2

blog.eidinger.info

 

 

Failure accessing the Photo librar… | Apple Developer Forums

Before iOS 15.2 version we could register PHPhotoLibrary.shared().register(self) without authorization, in iOS 15.2 it is not possible, you will get an error. You have to request authorization(requestAuthorization(_:)) for register PHPhotoLibrary.shared().

developer.apple.com