Skip to content

[기술공유] 카메라 및 사진 권한 물어보기

박효준 edited this page Nov 14, 2024 · 1 revision

문제 상황

인터넷 세상에서 나 빼고 모두가 카메라 권한을 AVCaptureDevice.requestAccess(for: .video, completionHandler: (Bool) -> Void) 을 사용하여 확인하고 있었다. (진짜 세상이 나한테 구라치는줄;; like 트루먼쇼..)

하지만 내가 쓰기만 하면 아래와 같은 에러가 나왔다.

스크린샷 2024-11-14 오후 11 23 31

설상가상 위 에러는 디버깅도 힘들고 정확히 어떤 이유에서 나는 에러인지 알기 힘든 메세지라 정말.. 힘들었다..


문제 해결

결론부터 말하자면 저 에러는 프로젝트를 Swift6로 migration하면서 나오는 에러였다.

먼저 디버깅을 통해 AVCaptureDevice.requestAccess가 있는 줄까지는 잘 실행됐다가 이후 후행 클로저가 실행되면서 앱이 터진다는 사실을 알 수 있었다.

항상 후행 클로서가 main이 아닌 다른 스레드에서 돌아가다가 터지길래 main thread에서 돌아가야하는 코드가 background에서 돌아가서 그런가.. 싶어서 Task { @MainActor }DispatchQueue.main.async 를 사용해서 내부 코드를 묶어줬는데 그럼에도 불구하고 계속해서 터졌다..

여기서 이제 반쯤 포기하고 PHPhotoLibraryChangeObserver 라는 앨범에 사진이 바뀌는 것을 옵저빙하는 프로토콜 구현을 하고 있었다.

위 프로토콜은 func photoLibraryDidChange(_ changeInstance: PHChange) 라는 함수를 필수로 구현해줘야했는데, 함수를 호출하니 아래와 같은 에러 메세지가 떴다.

스크린샷 2024-11-14 오후 11 23 40

@preconcurrency 키워드를 붙이는 것은 내가 알기로 그냥 임시방편? 느낌으로 완전히 안전하지 않은 방법이라 위의 방법을 사용해 nonisolated라는 키워드를 함수 앞에 붙여줬다.

저 에러가 정확히 왜 일어나는지 그냥 궁금해져서 (평소라면 걍 지나쳤을텐데.. 왠지모르게 검색해보고 싶어졌음) 구글링을 했더니 아래와 같은 답이 있었다.

스크린샷 2024-11-14 오후 11 23 55

근데 여기서 갑자기 번 - 쩍 생각이 들면서 혹시?? 뭔가 컴파일러는 잡지 못했지만 저 requestAccess의 후행클로저가 nonisolated하게? 돌아가야하는건가? 설마? 라는 생각이 들어 (왜 이런 생각이 갑자기 들었는지는 나도 실은 잘 모르겠다) 클로저를 nonisolated하게 하는 법? 을 찾아봤고 클로저에 @Sendable 키워드를 붙이라는 글을 보게 되었다.

무튼 아래 코드와 같이 후행 클로저에 @Sendable을 붙여주었더니 ?!

AVCaptureDevice.requestAccess(for: .video) { @Sendable granted in
    if granted {
        print("Camera Authorization Granted")
    } else {
        print("Camera Authorization Denied")
    }
}
스크린샷 2024-11-14 오후 11 24 08

ㅠㅜㅜㅠㅜㅠㅜㅠㅜㅠㅜㅠㅜㅠㅜㅠ 성- 공 💥

아ㅏㅏ놔 ㅜㅠㅜㅠㅜㅠㅜㅜ어제 나의 3시간 가량이.. 헛수고가 아니었…던건 아니지만 무튼 실행됐다 ㅠㅜㅠㅜㅠ

솔직히 isolated와 sendable의 상관관계..를 잘 아는게 아니라 저게 어째서 된 것인지 완벽하게 파악하진 못해서 해당 부분에 대해선 조금 더 학습이 필요할 것 같다.

아무튼 성공함 ~


배운 점

Swift6 이친구…진짜 쉽지않다;;

Sendable과 isolated 개념을 더… 공부해라..


참조 링크

https://forums.developer.apple.com/forums/thread/758181

https://stackoverflow.com/questions/73517387/swift-non-actor-isolated-closures

Clone this wiki locally