본문 바로가기

iOS

[iOS] UIImagePickerCotroller 문서 훑고 맛보기

UIImagePickerController

사진을 찍고, 동영상을 녹화하고 사용자의 미디어라이브러리 항목을 선택하기위한 VC임

뭔소린지 추상적이라서 더 자세히 읽어보도록 하자

Declaration @MainActor class UIImagePickerController : UINavigationController

일단 네비게이션컨트롤러를 상속받고있는 클래스임…ㅇㅎ

[개요]

  • UIImagePickerController는 사용자의 상호작용을 하고 이러한 결과를 대리자개체에 전달한다.
  • 이미지 선택하는 Controller의 역할과 모양은 presentation하기이전에 할당한 자원 타입에 따라 다르다…? => 설정 하기에따라 모양이 다르다는소리같음…
    • UIImagePickerController.SourceType.camera의 sourceType은 새로운 사진이나 영상을 찍기위한 기능이다.
    • UIImagePickerController.SourceType.PhotoLibrary또는 .savedPhotosAlbum은 저장된 사진과 동영상중에서 선택하기위한 기능이다.

기본컨트롤이포함된 이미지 선택하는 Controller를 사용하려면 이와같은 단계를 거치면된다.

  1. 자원으로부터 컨텐츠를 선택할 수 있는 자격이 있는지 장치를 검사한다.
    • isSourceTypeAvailable클래스 메서드를 호출하여 UIImagePickerController.SOurceType열거에서 상수를 제공하여 이를 수행할 수 있다.
  2. availableMediaTypes(for:)클래스메서드를 호출하여 사용중인 소스에 사용할 수 있는 미디어 유형을 확인합니다.
    • 이를 통해 동영상 촬영에 사용할 수 있는 카메라와 정지 이미지에만 사용할 수 있는 카메라를 구분할 수 있습니다.
  3. mediaTypes속성을 설정해 UIImagePickerController에 사용가능하게 하려는 mediaType (stillImages, movies, both)에 따라 UI를 조정하도록 설정할 수 있습니다.
  4. iPhone or iPod touch에서 화면을 넘길때 modal()로 present하여 화면을 수행합니다.
  5. 사용자가 찍은 사진 이나 저장된 이미지 또는 동영상을 선택하기위해 탭버튼을 누르거나 또는 취소버튼을 누르는 경우에 IPC는 delegate를 사용합니다.
    • 이전에 저장한 이미지이거나 새로캡처한 데이터를 사용할 수 있음

IMPORTANT

UIIMAGEPICKERCONTROLLER클래스는 세로모드만 지원합니다. 이 클래스는 있는 그대로 사용하기위한것이며 서브클래싱을 지원하지않습니다. 그래서 이 클래스의 보기계층 구조는 비공개이며 한 가지예외를 제외하고는 수정해서는 안됩니다. cameraOverlayView 프로퍼티 뷰를 커스텀하거나 사용하겨 추가정보를 제공하는 카메라 인터페이스와 코드간의 상호작용을 관리할 수 있습니다.

delegate 객체를 지원합니다.

추가적으로 영상찍는거나 라이브사진작업 그리고 플래시모드 등의 작업에관한내용은 현재 작업하지는 않을것같아 나중에 필요할때 참고해보자

UIImagePicker사용해서 album에서 사진 가져오기


  1. Info에서 이 두가지 기능을 추가한다.
    설정방법: (info파일 클릭 -> Information Property List 오른쪽 +버튼 클릭 -> 아래 내용을 입력하면 목록이나옴 -> 선택하면됨)
    Privacy - Camera Usage Description (= 카메라 사용을 허용해주세요라고 설정하는것)
    Privacy - PhotoLibraryAddUsageDescription (= 사진앨범 가져오게 허용해주세요라고 설정하는것)
  2. 뷰컨에 두 가지를 상속해준다.
  • UIImagePickerControllerDelegate(= 이미지를 선택하고 카메라를 찍었을때 다양한 동작을 도와줌)
  • UINavigationControllerDelegate(=앨범 사진을 선택했을때, 화면 전환을 네비게이션으로 이동함)

시뮬레이터는 카메라에 접근하려고 메서드를 실행하면 에러가 발생한다. 추측이지만 시뮬레이터는현재…카메라기능 지원이 안되기에 오류가 발생하는 것같음
그래서 presentAlbum()메서드만 확인해볼것이다!

class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
	@IBOutlet var profileImageView: UIImageView!
	
	var count = 0
	
	override func viewDidLoad() {
    super.viewDidLoad()
    actionSheetAlert()
  }
  
  private func actionSheetAlert() {
    DispatchQueue.main.async {
      let alert = UIAlertController(title: "선택",
                                    message: nil,
                                    preferredStyle: .actionSheet)
      let cancel = UIAlertAction(title: "취소",
                                 style: .cancel)
      let camera = UIAlertAction(title: "카메라",
                                 style: .default) { [weak self] (_) in
        self?.presentCamera()
      }
      let album = UIAlertAction(title: "앨범",
                                style: .default) { [weak self] (_) in
        self?.presentAlbum()
      }
      alert.addAction(cancel)
      alert.addAction(camera)
      alert.addAction(album)
      
      self.present(alert, animated: true, completion: nil)
    }
  }
  // 이코드는 카메라에 접근하기위한 코드인데 시뮬레이터로 이메서드를 실행하면 에러가발생한다.. 뇌피셜이지만 실폰이아니기에 카메라자체가 없어서 그런것같다.
  private func presentCamera() {
    let ipc = UIImagePickerController()
    ipc.sourceType = .camera
    ipc.delegate = self
    ipc.allowsEditing = true
    ipc.cameraFlashMode = .on
    
    present(ipc, animated: true)
  }
  
  private func presentAlbum() {
    let ipc = UIImagePickerController()
    ipc.sourceType = .photoLibrary
    ipc.delegate = self
    ipc.allowsEditing = true // 사용자편집 가능여부
    
    present(ipc, animated: true)
  }
  
  // 기본적으로 제공하는 메서드임: 취소버튼 눌렀을때 화면을 사라지게해주는 기능
  func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
    dismiss(animated: true)
  }
  
  // 기본적으로 제공하는 메서드: 카메라나 앨범등 PickerController가 사용되거나 이미지 촬영을 하게되면 실행되는 기능
  // 카메라나 앨범에서 사용하기 버튼을 눌렀을때, info에 설정에 따라서 image가 저장됩니다. 그리고 dismiss로 메모리에서 지워줘야합니다.
  func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    
    dump("picker -> \(String(describing: info[UIImagePickerController.InfoKey.imageURL]))")
    
    if self.count % 2 == 0 {
      if let image = info[.editedImage] as? UIImage {
        self.profileImageView.image = image
      }
    } else {
      if let image = info[.originalImage] as? UIImage {
        self.profileImageView.image = image
      }
    }
    self.count += 1
    print(self.count)
    dismiss(animated: true)
    actionSheetAlert()
  }
}
 

실행화면

에러 발생 및 문제해결

  • actionSheetAlert()메서드를 실행하게되면

Attempt to present UIAlertController whose view is not in the window hierarchy 이러한 에러메세지와함께
앱에서 얼럿이 보이질 않는다…

그래서 stackOverflow 에 찾아보니 DispatchQueue.main.async내에 감싸줬더니 오류해결이 되었다. 그런데 왜안되는지에대해서는 stackOverflow에 나와있지는 않는것같았다. 🤔🤔🤔

Reference