본문 바로가기
IOS App Programming/IOS 연습

[IOS] 카메라, 갤러리 접근해서 사진 가져오기 - UIImagePickerController

by B_Tori 2023. 4. 6.

실행 결과

 

버튼을 통해서 이미지를 추가하고 추가한 이미지를 화면에 띄워준다.

 

레이아웃

상단에 네비게이션 바를 추가해 주고, add형식의 바버튼을 추가해 준다.

화면 중앙에는 UIImageView를 추가한다.

 

아웃렛 변수 및 액션 함수 추가

1. 선택한 이미지 뷰를 출력해 주기 위해 이미지 뷰의 아웃렛 변수 연결한다.

2. 버튼을 통해 이미지 추가 동작을 실행할 것이므로 버튼에 액션 함수를 연결한다.

 

Add 버튼

@IBAction func addBtnClick(_ sender:UIButton){
        let alert =  UIAlertController(title: "Title", message: "message", preferredStyle: .actionSheet)
        let library =  UIAlertAction(title: "앨범에서 가져오기", style: .default) { (action) in self.openLibrary() }
        let camera =  UIAlertAction(title: "카메라", style: .default) { (action) in self.openCamera() }
        let cancel = UIAlertAction(title: "취소", style: .cancel, handler: nil)
        alert.addAction(library)
        alert.addAction(camera)
        alert.addAction(cancel)
        present(alert, animated: true, completion: nil)
    }

add 버튼을 눌렀을 때 카메라에 들어갈지 앨범에 들어갈지 선택하게 선택하는 actionSheet를 생성한다.

UIAlertController의 preferredStyle을 actionSheet로 선택해 actionSheet 알림 창을 생성한다.

생성되는 버튼은 카메라, 앨범에서 가져오기 두 가지이므로 두 가지의 UIAlertAction을 생성하고 각각의 함수를 연결해 준다.

openLibrary()와 openCamera()는 각각의 버튼을 클릭 시 앨범 혹은 카메라로 연결해 주는 사용자 정의 함수이다. (뒤에 구현 내용 정리)

생성한 버튼을 alert에 연결해 준 뒤 alert으로 화면을 전환한다.

 

권한 설정

카메라, 앨범 등 사용자 정보에 접근하기 위해서는 권한 요청이 필요하다.

info.plist에 들어가 위의 두 가지 권한을 추가해 준다.

  • Privacy - Photo Library Usage Description : 사진앨범 권한
  • Privacy - Camera Usage Description : 카메라 권한

 

델리게이트 설정

class ViewController: UIViewController {

...

let imgPicker = UIImagePickerController()

...

override func viewDidLoad() {

    super.viewDidLoad()

    imgPicker.delegate = self

}

...

extension ViewController : UIImagePickerControllerDelegate,

UINavigationControllerDelegate{

}

imgPicker라는 UIImagePickerController를 생성해 준다. 이는 카메라나 앨범에서 사진을 고를 수 있도록 하는 뷰컨트롤러이다.

imgPicker의 델리게이트를 뷰컨트롤러로 연결해 준다.

그리고 이미지피커를 사용하기 위해서는 두 가지 델리게이트를 연결해주어야 한다.

1. UIImagePickerDelegate

Image Picker와 상호작용하기 위해 반드시 구현해야 하는 메서드의 집합으로 이미지를 고르는 다양한 이벤트에 대한 동작을 지원받는다.

 

2. UINavigationControllerDelegate

갑자기 네비게이션 컨트롤러의 델리게이트를 왜 사용해야 하는지 의문이었다.

이는 화면 전환 동작에 대한 지원을 하는데 이미지 피커에서 사진을 선택할 때, 취소하고 원래 뷰 컨트롤러로 돌아올 때 등의 작업을 처리하기 위해 채택해야 한다고 한다.

openCamera, openLibrary() 구현

func openLibrary(){
    imgPicker.sourceType = .photoLibrary
    present(imgPicker, animated: false, completion: nil)
}
func openCamera(){
    imgPicker.sourceType = .camera
    present(imgPicker, animated: false, completion: nil)
}

이미지 피커의 sourceType을 각각 라이브러리와 카메라로 설정해준 뒤 이미지 피커로 화면을 전환해 준다.

 

여기까지 구현하게 되면 버튼 클릭 시 이미지 선택 창이 나와 이미지를 고를 수 있게 된다.

 

이미지 뷰에 가져온 이미지 설정하기

이제 선택한 이미지를 가져와 이미지 뷰에 설정해 보겠다.

이는 델리게이트에 정의되어 있는 didFinishPickingMediaWithInfo를 통해 설정할 수 있다.

이 메서드는 이름에서 알 수 있듯이 사용자가 사진을 다 고르게 되면 다양한 정보와 함께 호출된다.

extension ViewController:UIImagePickerControllerDelegate,UINavigationControllerDelegate{
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage{
            imgView.image = image
            //print(info)
            
        }
        dismiss(animated: true, completion: nil)
    }
}

우선 위와 같은 코드를 작성하기 전에 info를 출력해 보면

위와 같은 딕셔너리 형태의 정보가 제공된다.

UIImage를 얻기 위해서는 맨 마지막에 있는 UIImagePickerControllerOriginalImage를 사용하면 된다.

키 값은 UIImagePickerController.InfoKey.originalImage로 사용하면 된다.

따라서 옵셔널 바인딩을 통해 옵셔널 래핑을 풀어주고 이미지뷰의 이미지를 해당 이미지로 설정해 준다.

dismiss를 통해서 이미지 피커의 화면을 닫아준다.

 

(추가) 카메라 사용불가 예외 처리

시뮬레이터에서는 카메라를 사용할 수 없기 때문에 실제 아이폰이 아니라 시뮬레이터에서 이를 확인하면 카메라 선택 시 에러를 발생하게 된다.

따라서 이 부분에 대해서 예외처리를 추가적으로 해주었다.

enum CameraError : Error{
    case notAvailable
}

우선 카메라 접근 불가라는 에러 유형을 하나 만들어주었다.

func openCamera() throws{
    guard UIImagePickerController .isSourceTypeAvailable(.camera) else {
        throw CameraError.notAvailable
    }
    imgPicker.sourceType = .camera
    present(imgPicker, animated: false, completion: nil)
}

그리고 오류가 발생하는 openCamera함수를 위와 같이 고쳐 오류를 던져준다.

@IBAction func addBtnClick(_ sender:UIButton){

    ...
    
    let camera =  UIAlertAction(title: "카메라", style: .default) { (action) in
        guard (try? self.openCamera()) != nil else{
            let alert = UIAlertController(title: "카메라 접근 실패", message: "카메라를 이용할 수 없습니다.", preferredStyle: .alert)
            let okButton = UIAlertAction(title: "OK", style: .default, handler: nil)
            alert.addAction(okButton)
            self.present(alert, animated: false, completion: nil)
            print("Camera Not Available")
            return
        }
    }
    
    ...
    
}

그리고 openCamera함수를 실행해 주는 부분에 가 위와 같이 고쳐준다.

만약에 오류가 발생한다면 카메라를 실행하지 못한다는 alert을 띄워준다.

댓글