[iOS] - 이미지 피커 컨트롤러(Image Picker Controller)

LEEHAKJIN-VV·2022년 7월 5일
3

iOS 정리

목록 보기
1/7

본 글은 꼼꼼한 재은씨의 Swift 기본편을 학습하고 정리한 내용입니다.

이미지 피커 컨트롤러(Image Picker Controller)

이미지 피커 컨트롤러는 카메라나 앨범을 통해 이미지를 선택할 때 사용하는 컨트롤러이다. 그리고 델리게이트 패턴을 활용한다.

이 컨트롤러 자체는 단순히 이미지를 선택해서 가져오는 기능을 가진다. 하지만 source type에 따라 즉석에서 촬영한 사진 or 앨범에 저장된 사진 or 동영상을 가져올 수도 있다.

위의 다양한 기능들은 이미 컨트롤러 내에 구현되어 있으므로 소스 타입만 설정하여 사용할 수 있다. 또한 이미지 피커 컨트롤러는 화면 전체를 덮기 때문에 운영체제가 일시적으로 앱에 대한 control을 가진다.

control을 가진 운영체제는 사진을 찍거나, 앨범에서 사진을 가져오면, 가져온 이미지를 델리게이트로 지정된 객체에 메소드 호출을 통해 인자 값으로 전달한다. 그러면 앱은 전달받은 결과를 사용할 수 있다.

UIImagePickerController 클래스

이미지 피커 기능은 UImagePickerController 클래스에 구현되어 있다. 이 클래스는 UIViewController를 상속받은 컨트롤러이기 때문에 실행할 때는 화면을 전환하는 방식을 사용한다.

아래는 UIViewController클래스의 인스턴스를 생성하고, 속성을 설정한 다음 실행하는 코드이다.

위 코드에서 picker의 타입을 photoLibrary로 지정하는 것을 확인할 수 있다. 이는 소스타입 의 한 종류로, 몇 가지 열거형 타입이 있다.

  • camera: 이미지 피커 컨트롤러의 소스로 장치의 내장 카메라를 지정한다.
  • photoLibrary: 이미지 피커 컨트롤러의 소스로 장치의 포토 라이브러리를 지정한다.
  • savedPhotosAlbum: 이미지 피커 컨트롤러의 소스로 장치의 카메라 롤 앨범을 지정한다.

여기서 보면 photoLibrarysavedPhotosAlbum의 차이가 무엇인지 궁금할 수도 있다.(본인은 그랬음) 그래서 알아본 결과 camera roll이란 단어를 알아야 하는데 이는 카메라 앨범을 지칭하는 단어이다.

photoLibrary는 많은 앨범 중 1개를 사용자가 선택하는 것이고 savedPhotosAlbum는 여러 가지 앨범 중 카메라 앨범으로 이미 선택되어 있는 것이다.

3가지 중 2가지 case photoLibrary. savedPhotosAlbum는 deprecated될 예정이므로 PHPickerViewController를 사용하는 것을 애플에서 권장한다. 그러나 본 글에서는 해당 클래스는 다루지 않는다.

나머지 속성을 간단하게 설명하면 allowsEditing속성은 가져온 소스(데이터)의 편집 여부이다. default는 false의 값을 가지며 true값을 할당하면 편집한 소스를 사용한다는 의미이다.

delegate속성은 선택한 소스를 반환받을 대상을 지정하는 속성이다. 여기서는 self를 지정하였으므로 자기 자신의 뷰 컨트롤러로 소스를 받겠다는 의미이다.

선택한 이미지는 메서드를 통해 전달받게 되므로 다음 2가지 델리게이트 프로토콜을 구현해야 한다.

  1. UImagePickerControllerDelegate 프로토콜
  2. UINavigationControllerDelegate 프로토콜

이 프로토콜의 메소드를 통해서 받은 소스를 처리할 수 있다.

이미지 가져오기 실습

이제 이미지를 가져오는 실습을 해보자.

실습을 진행하기 전에 info파일에서 권한 설정이 필요하다. iOS11 이전에는 앨범에 접근, 사진 촬영을 사용하기 위해 2가지 모두 권한 설정이 필요했는데 11이후로 사진 촬영만 권한이 필요하다.

PHPickerViewController를 사용하는 경우에는 앨범에 접근하기 위해 권한이 필요하다. 그러나 본 글에서는 imagepickercontroller를 사용하기 때문에 카메라 관련 권한만 설정한다.

위 사진처럼 value에 권한을 요청할 때 사용하는 메시지를 작성하면 된다.

이제 권한 설정을 끝냈으니 이미지를 담은 imageView객체를 스토리보드에 추가하자.

imageView객체는 화면상에 이미지를 표현하는 객체이다. 이 객체의 아울렛 변수를 선언하고, 버튼을 클릭했을 때 이미지를 선택하는 액션 메소드를 아래와 같이 선언한다.

이제 버튼을 눌러 이미지를 선택해 보자.

다음과 같이 포토앨범에서 사진을 선택할 수 있는 것을 확인할 수 있다. 그러나 아직 델리게이트 메소드를 선언하여 가져온 이미지를 처리하는 소스를 구현하지 않았으므로 이미지 뷰에 이미지가 보이지 않는다. 이를 처리하기 위해 2가지 메소드를 선언한다.

메소드를 구현하기 전에 delegate속성값을 자기 자신의 뷰 컨트롤러로 지정하는 것을 까먹지 말자

우리가 사용할 메소드는 2가지다.

imagePickerController(_: didFinishPickingMediaWithInfo:)메소드에서 첫 번째 인자 값은 이 메소드를 호출하는 이미지 피커 컨트롤러 객체이다. 이 객체를 이용하여 2개 이상의 이미지 피커 컨트롤러가 사용되는 경우 서로 구분할 수 있다. 두 번째 인자 값은 우리가 원하는 이미지에 대한 데이터(소스)이다. 이는 딕셔너리 형태로 구성되어 있기 때문에 적절한 키를 사용하여 원하는 데이터를 얻을 수 있다.

아래는 키에 대한 정보 중, 몇 가지를 소개한다. 우리 예제에서는 editedImage 타입 프로퍼티를 사용한다.

  • UIImagePickerController.InfoKey.mediaType : 전달받는 미디어 타입에 대한 정보

  • UIImagePickerController.InfoKey.originalImage: 선택한 원본 데이터(수정이 되었더라도 원본 데이터를 얻을 수 있음)

  • UIImagePickerController.InfoKey.editedImage: 데이터가 수정된 경우 수정된 데이터 전달

이제 이 두 가지 메소드를 이용하여 앨범에서 선택한 이미지를 이미지 뷰에 표시하자.

imagePickerControllerDidCancel 메소드

글의 초반부에서 언급했듯이, 이미지 피커 컨트롤러는 UIViewController를 상속받기 때문에 화면을 전환하는 방식을 사용하다. 그래서 위 예제에서는 present메소드를 이용하여 컨트롤러를 실행하고 dismiss 메소들 이용하여 창을 닫는다.

이미지를 선택하지 않고 취소한 경우 imagePickerControllerDidCancel 메소드가 호출되는 데 이때는 열었던 이미지 피커 컨트롤러 창을 닫아 이전의 뷰 컨트롤러로 복귀해야 한다. 그리고 이 작업을 명시적으로 구현해야 한다. 이유는 델리게이트 메소드를 구현한 경우에는 자동으로 컨트롤러 창이 닫히지 않기 때문이다. (델리게이트 메소드를 구현하지 않은 경우 취소 버튼을 누르면 자동으로 창이 닫힘)

현 예제에서는 dismiss 메소드를 이용하여 창을 닫고, 아래와 같이 알림 창을 만들어 사용자에게 표시한다.

imagePickerController(_: didFinishPickingMediaWithInfo:)메소드

이미지 파커가 앨범에서 이미지를 선택했다면 선택한 이미지를 가져와야 한다. 이는 이전에 설명하였던 컨트롤러의 InfoKey의 타입 프로퍼티를 사용하여 얻는다. 컨트롤러를 선언할 때 편집 여부를 true로 할당하였기 때문에 editedImage 프로퍼티를 이용하여 이미지를 가져온다. 타입은 Any타입이기 때문에 UImage타입으로 캐스팅한다. 그리고 가져온 이미지를 아울렛 변수인 imgViewimage프로퍼티에 할당하면 화면에 이미지가 나타난다.

이미지가 선택된 모습

ViewController.swift 파일 전체 코드

//
//  ViewController.swift
//  Delegate-ImagePicker
//
//  Created by 이학진 on 2022/07/05.
//

import UIKit

class ViewController: UIViewController , UINavigationControllerDelegate{
    @IBOutlet var imgView: UIImageView!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
    
    @IBAction func pick(_ sender: Any) {
        // 이미지 피커 컨트롤러 생성
        let picker = UIImagePickerController()
        picker.sourceType = .photoLibrary // 이미지 소스로 사진 라이브러리 선택
        picker.allowsEditing = true // 이미지 편집 기능 On
        // 델리게이트 지정
        picker.delegate = self
        
        // 이미지 피커 컨트롤러 실행
        self.present(picker, animated: false)
    }

}

extension ViewController: UIImagePickerControllerDelegate {
    // 이미지 피커에서 이미지를 선택하지 않고 취소했을 때 호출되는 메소드
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        // 이미지 피커 컨트롤러 창 닫기
        print("이미지 선택하지않고 취소한 경우")
        
        self.dismiss(animated: false) { () in
            // 알림 창 호출
            let alert = UIAlertController(title: "", message: "이미지 선택이 취소되었습니다.", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "확인", style: .cancel))
            self.present(alert, animated: false)
        }
    }
    // 이미지 피커에서 이미지를 선택했을 때 호출되는 메소드
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        print("이미지 선택")
        // 이미지 피커 컨트롤러 창 닫기
        picker.dismiss(animated: false) { () in
            // 이미지를 이미지 뷰에 표시
            let img = info[UIImagePickerController.InfoKey.editedImage] as? UIImage
            self.imgView.image = img
        }
    }
}

참고자료

https://developer.apple.com/documentation/uikit/uiimagepickercontrollerdelegate/
https://developer.apple.com/documentation/uikit/uinavigationcontrollerdelegate/
https://developer.apple.com/documentation/uikit/uiimagepickercontroller

0개의 댓글