Picture App

Photo와 Camera 같이 사용자의 개인정보에 접근하기 위해서는 사용자로부터 권한 승인을 먼저 받아야 한다.

info.plist에 NSCameraUsageDescription와 NSPhotoLibraryUsageDescription 의 값에 적절한 문구를 추가한다.

SwiftUI 에서는 PhotosUI 라는 프레임워크로 사진에 쉽게 접근할 수 있지만, 이번에는 UIKit의 UIViewControllerRepresentable 코드를 사용해보고자 한다.

 struct ImagePicker: UIViewControllerRepresentable {
     var sourceType = UIImagePickerController.SourceType.camera
     @Binding var chosenImage: UIImage
     @Environment(\.presentationMode) var presentationMode

     func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
         let myImagePicker = UIImagePickerController()
         myImagePicker.sourceType = sourceType
         myImagePicker.delegate = context.coordinator
         return myImagePicker
     }

     func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
     }

     func makeCoordinator() -> Coordinator {
         Coordinator(self)
     }
 }

 class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
     var imagePicked: ImagePicker

     init(_ imagePicked: ImagePicker) {
         self.imagePicked = imagePicked
     }

     func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
         if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
             imagePicked.chosenImage = image
         }
         imagePicked.presentationMode.wrappedValue.dismiss()
     }
 }

적용 예시 코드

struct ContentView: View {
    @State private var showSheet = false
    @State private var image = UIImage()
    @State private var sourceType: UIImagePickerController.SourceType = .photoLibrary
    
    var body: some View {
        VStack {
            Image(uiImage: self.image)
                 .resizable()
                 .scaledToFill()
                 .frame(minWidth: 0, maxWidth: .infinity)

            HStack {
                 Button(action: {
                     showSheet = true
                     sourceType = .photoLibrary
                 }) {
                     Text("Photo library")
                         .font(.title2)
                 }
                 Spacer()
                 Button(action: {
                     showSheet = true
                     sourceType = .camera
                 }) {
                     Text("Camera")
                         .font(.title2)
                 }
            }
            .padding()
         }
         .padding()
         .sheet(isPresented: $showSheet) {
             ImagePicker(sourceType: sourceType, chosenImage: $image)
                 .ignoresSafeArea()
         }
    }
}

Coordinator는 UIKit의 Delegate 패턴 등을, SwiftUI의 선언형 프레임워크의 패턴에 맞춰주도록 하는 애플에서 제공하는 기능이다. 다시 말해 UIRepresentable과 SwiftUI를 이어주는 class.

PhotosUI 사용

photosUI