[iOS] PhotoKit 활용 - 갤러리 사진 가져오기 (2/2)

2020. 10. 9. 00:19iOS

반응형

저번 iOS 포스팅에서는 PhotoKit을 활용하는 직접적인 방법보다는 어떤 레퍼런스가 있고 어떤 역할을 하는지 다뤘었죠.

이번에는 제가 사용했던 코드를 보고 사용하는 방법을 간단히 알아볼게요.

 

저번 포스팅을 보시지 않으신 분은 이전 글을 참고해주세요.

 

[iOS] PhotoKit 활용 - 갤러리 사진 가져오기 (1/2)

이번에 SKT 공모전 앱을 개발하면서 커스텀 된 카메라를 만들고 촬영한 사진을 iPhone의 사진에 저장하여야하는 기능이 있었습니다. 보통 카메라를 사용하거나 iPhone의 사진에 접근할 때, 다들 UIPic

dongminyoon.tistory.com


우선 PhotoKit을 사용하기 전에 최초로 설정하여야하는 것은 무엇일까요..⁉️

 

한 번, 예전 포스팅에서 했던 Core Location을 생각해보면 Device의 정보를 얻어오는 것이기 때문에 권한 허용이 필요했죠..⁉️

Info.plist에서 이를 설정해주었는데, PhotoKit도 동일합니다.

 

iPhone Device의 갤러리에 접근하는 것이기 때문에, 접근 권한을 허용해주어야합니다.

 

갤러리 접근 요청

한 번 요청을 묻는 과정을 같이 보겠습니다.

 

1️⃣Info.plist에 접근하여 그림과 같이 해당 부분을 추가해줍니다.

Value의 값은 권한을 물을 때, 왜 사용하는지 사용자에게 설명하는 부분입니다. 

이 부분이 왜 권한을 허용해야하는지 자세한 설명이 없으면 리젝이 날 수 있어요,,,,

 

2️⃣사용자에게 최초로 갤러리 접근이 필요한 시점에 권한을 요청합니다. (저는 viewDidLoad에서 요청하도록 했습니다.)

override func viewDidLoad() {
    switch PHPhotoLibrary.authorizationStatus() {
    // 사용자가 접근을 허용했을 때
    case .authorized:
    // 사용자가 아직 권한에 대한 설정을 하지 않았을 때
    case .notDetermined:
    	// 다시 한 번 권한을 요청 -> 권한이 허용되고 할 Completion을 작성
        PHPhotoLibrary.requestAuthorization { status in
            switch status {
            case .authorized:
            case .notDetermined:
            case .restricted:
            case .denied:
            case .limited:
            @unknown default:
            }
    }
    case .denied:
    // 접근이 거부된 경우
    case .limited:
    // 갤러리의 접근이 선택한 사진만 허용된 경우
    @unknown default:
        fatalError()
}

 

저는 갤러리 접근을 최초 ViewController을 불러올 때, 사용하기 때문에 한 번만 최초로 요청할 수 있도록 하였습니다.

또한 만약 .notDetermined 상태로 아직 사용자가 선택을 하지 않았으면 요청을 보낼 수 있도록 하였습니다.

 

여기서 위의 각 case 분기에 여러분들이 작동하길 원하는 동작들을 넣으시면 됩니다.

(예로, 저는 self.popViewController(animated: true)로 해당 VC을 사용할 수 없게 하였습니다. 각자 앱마다 다르겠죠.)

 

갤러리로부터 사진 가져오기

접근 요청을 완료했으니 이제 직접적으로 사진을 가져오면 되겠죠.

 

제가 앱을 만들 때 사용했던 위주로 알려드리겠습니다.

우선, 권한이 허용되면 최근 사진 한 장을 갤러리로부터 가져온 후 화면에 보여주었습니다.

그러나 만약 권한이 거부당하면, 디폴트 이미지를 보여주고 다시 사진을 요청할 때 권한을 물을 수 있도록 하였습니다.

 

먼저, 최근 사진을 가져오는 코드를 볼게요.

 

✔️최근 사진 한 장 가져오기

private func setPhotoLibraryImage() {
    let fetchOption = PHFetchOptions()
    fetchOption.fetchLimit = 1
    fetchOption.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
    let fetchPhotos = PHAsset.fetchAssets(with: fetchOption)
    if let photo = fetchPhotos.firstObject {
        DispatchQueue.main.async {
            ImageManager.shared.requestImage(from: photo, thumnailSize: self.galleryButton.frame.size) { image in
            // 가져온 이미지로 (image 파라미터) 하고싶은 행동
            }
       }
    } else {
        // 사진이 없을 때, 디폴트 이미지 지정
        self.galleryButton.setImage(UIImage(named: ImageKey.noGallery), for: .normal)
    }
}

여기서 저번 시간에 보았던 PHFetchOptions을 사용하였죠⁉️

 

바로 원하는 데이터를 가져오기 위해 Query문을 통해 설정을 할 수 있어요.

 

저는 최근 사진을 한 장 가져오면 되었기 때문에, 숫자를 지정하고 가장 최근 순으로 정렬해서 가져올 수 있게 하였습니다.

Predicate을 활용해서 더 다양한 방법이 가능합니다. 필요에 맞게 사용해주세요.

 

그리고 가져온 PHAsset을 통해 이미지를 표시했어요.

 

그러나 여기서 PHAsset은 메타데이터일뿐이지 이미지의 값은 없다고 한 것 기억하시죠?

여기서 필요한 것이 PHImageManager입니다.

 

PHAsset으로부터 사진을 가져올 수 있게 도와주는 친구에요.

저는 PHImageManager을 사용하기 위해 Singloton 패턴을 사용해서 구현했어요.

 

✔️PHAsset으로부터 사진 Image가져오기

import Photos

class ImageManager {
    static let shared = ImageManager()
    
    private let imageManager = PHImageManager()
    
    func requestImage(from asset: PHAsset, thumnailSize: CGSize, completion: @escaping (UIImage?) -> Void) {
        self.imageManager.requestImage(for: asset, targetSize: thumnailSize, contentMode: .aspectFill, options: nil) { image, info in
            completion(image)
        }
    }
}

여기까지 따라하셨으면 이제 갤러리로부터 사진을 가져오는 것은 완료가 되었습니다.

 

여기서 제가 추가적으로 사용하였던 기능이 있습니다.

바로 갤러리에 변화가 있을 때, 이를 반영해서 최근 사진을 다시 가져오는 것입니다.

 

방법은 옵저버를 사용해서 PHPhotoLibrary 객체에 등록하는 것입니다.

 

사용을 위한 절차를 알아볼까요⁉️

 

1️⃣우선 사용을 위해 접근이 허용되었을 때, 해당 ViewController을 옵저버로 등록합니다.

 

2️⃣옵저버로 등록하기 위해 PHPhotoLibraryChangeObserve 채택합니다.

 

3️⃣갤러리의 변화가 감지되었을 때, 원하는 동작을 정의합니다.

 

다음과 같은 절차를 사용해서 원하는 동작을 구현할 수 있습니다.

코드로 알아볼게요.

 

✔️갤러리 변화 감지하기

override func viewDidLoad() {
    switch PHPhotoLibrary.authorizationStatus() {
    // 사용자가 접근을 허용했을 때
    case .authorized:
    	// 옵저버로 등록
        PHPhotoLibrary.shared().register(self)
}

extension CameraVC: PHPhotoLibraryChangeObserver {
    func photoLibraryDidChange(_ changeInstance: PHChange) {
    // 변화를 감지했을 때, 원하는 동작 설정
    }
}

 

 다음과 같이 사용해주시면 앱의 용도에 맞게 쉽게 코딩하실 수 있을 것 같습니다.

 

오늘은 PhotoKit의 사용에 대해 직접적으로 알아보았습니다.

제가 사용했던 앱의 기준에 맞춘거라 사용법이 살짝 다를 수 있지만 원하는 동작으로 살짝만 바꾸어 사용하시면 될 것 같습니다.

 

혹시 더 궁금한 점이나 틀린 점이 있으면 말씀해주세요 🙌

반응형