티스토리 뷰

iOS

[iOS] Photos 프레임워크 톺아보기

국산 앨런 2019. 8. 10. 18:11

iOS 개발을 하다보면 자연스레 갤러리에 접근하는 일이 많아집니다.

 

그래서 이번엔 iOS 에서 iCloud 사진 라이브러리를 포함하여 사진 및 비디오에 직접 접근,편집할 수 있는 프레임워크

 

Photos 에 대해서 알아보겠습니돠

 

먼저 Photos프레임워크에서 객체를 지칭하는 방식을 살펴보겠습니다 . Asset < Asset Collection < Collection List

 

Asset

Asset Collection

Collection List

 

각각의 모델 클래스(PHAsset, PHAssetCollection, PHCollectionList)의 인스턴스를 통해 작업하려는 항목에 접근할 수 있습니다.

 

가져오기 메스드에서 반환된 에셋 또는 컬렉션의 목록을 받을 수 있습니다. (PHFetchResult)

 

받아온 목록에 필터링, 정렬 등의 영향을 줄 수 있습니다. (PHFetchOptions)

 

사진 콘텐츠의 변경을 하려면 변경요청 객체( (PHAsset/PHAssetCollection/PHCollectionList)ChangeRequest)를 만들고 공유 객체(PHPPhotoLibrary)에게 요청을 해야합니다.

 

공유 객체를 사용하는 이유는 다수의 스레드, 애플리케이션에서 동일한 에셋을 사용하여 쉽고 안전하며 효율적으로 작업을 할 수 있기 때문입니다. 이 공유 객체는 권한을 주는 관리자 역할이라고 볼 수 있습니다.

 

사진의 정보를 변경할 때마다 변경 사항을 관찰할 수 있습니다. (PHPhotoLibraryChangeObserver, PHChange, PHObjectChangeDetails, PHFetchResultChangeDetails)

 

...

 

프레임워크 내 각 클래스의 설명을 요약해서 적어보았습니다.

 

...  역시 예제가 좋은 것 같아요

 

Example) 앨범 사진 지우기 그리고 리로드하기 !

프로젝트를 생성하고 사진첩 접근을 위한 설정을 해줍니다.

 

 

스토리보드는 이렇게 구성해주세요. Cell의 재사용을 위한 Identifier는 'cell'

 

 //ViewController.swift
 ...
 @IBOutlet weak var tableView: UITableView!
 var fetchResuls: [PHFetchResult<PHAsset>] = []	//앨범 정보
 let imageManager = PHCachingImageManager()	//앨범에서 사진 받아오기 위한 객체
 var fetchOptions: PHFetchOptions {
 	let fetchOptions = PHFetchOptions()
	fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
	return fetchOptions
 }	//앨범 정보에 대한 옵션
 ...

 

사용하게 될 변수들입니다.

 

func checkPermission() {
    switch PHPhotoLibrary.authorizationStatus() {
    case .authorized:
        self.requestImageCollection()
    case .denied: break
    case .notDetermined:
        PHPhotoLibrary.requestAuthorization({
            switch $0 {
            case .authorized:
                self.requestImageCollection()
            case .denied: break
            default:
                break
            }
        })
    default:
        break
    }
}

 

먼저 사진첩 접근에 대한 허가를 받고 그에 따른 처리를 해줍니다.

 

func requestImageCollection() {
    let cameraRoll = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .smartAlbumUserLibrary, options: nil)
    let favoriteList = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .smartAlbumFavorites, options: nil)
    let albumList = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .albumRegular, options: nil)
    addAlbums(collection: cameraRoll)
    addAlbums(collection: favoriteList)
    addAlbums(collection: albumList)
    
    OperationQueue.main.addOperation {
        self.tableView.reloadData()
    }
}

private func addAlbums(collection : PHFetchResult<PHAssetCollection>){
    for i in 0 ..< collection.count {
        let collection = collection.object(at: i)
        self.fetchResuls.append(PHAsset.fetchAssets(in: collection, options: fetchOptions))
    }
}

 

허가를 받고 나면 앨범에 대한 정보를 받고 tableView를 리로드 해줍니다.

 

extension ViewController: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return fetchResuls.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? UITableViewCell else {
            return UITableViewCell()
        }
        guard let asset = fetchResuls[indexPath.row].firstObject as? PHAsset else {
            return UITableViewCell()
        }
        
        imageManager.requestImage(for: asset, targetSize: CGSize(width: 100, height: 100), contentMode: .aspectFill, options: nil) { (image, _) in
            cell.imageView?.image = image
        }
        return cell
    }
}

 

tableView 셋팅은 간단합니다. 셀이 맞지 않거나 asset(=앨범의 정렬기준 첫번째 사진 정보) 이 없을 경우 셀을 비워줍니다.

 

imageManager를 이용하여 asset의 이미지정보를 UITableViewCell의 default로 있는 imageView의 이미지로 적용시켜줍니다.

 

override func viewDidLoad() {
	super.viewDidLoad()
	checkPermission()
	//PHPhotoLibrary.shared().register(self)
	tableView.delegate = self
	tableView.dataSource = self
}	

 

여기까지 하고 돌려볼까요 ??? (주석 처리한 부분은 밑에서 ..)

 

 

사진첩에 있는 귀여운 포켓몬들이 그대로 나오네요 ^----------------^

 

이제 사진첩에서 일어나는 변화를 모든 앱에게 전역적으로 알려주는 PHPhotoLibraryChangeObserver 를 사용하여

 

앨범의 사진 삭제 이벤트를 감지해보겠습니다.

 

override func viewDidLoad() {
	super.viewDidLoad()
	checkPermission()
	PHPhotoLibrary.shared().register(self)
	tableView.delegate = self
	tableView.dataSource = self
}

extension ViewController: PHPhotoLibraryChangeObserver {
    func photoLibraryDidChange(_ changeInstance: PHChange) {
        for i in 0..<self.fetchResuls.count {
            if let changes = changeInstance.changeDetails(for: fetchResuls[i]) {
                fetchResuls[i] = changes.fetchResultAfterChanges
            }
        }

        OperationQueue.main.addOperation {
            self.tableView.reloadData()
        }
    }
}

 

주석처리한 부분을 해제하고 PHPhotoLibraryChangeObserver 프로토콜을 채택해줍니다.

 

photoLibraryDidchange() 에서 사진첩의 변화를 감지할 수 있습니다.

 

변화를 결과인 changes.fetchResultAfterChanges 부분을 우리의 fetchResults[i] 에 적용시켜주고

 

테이블뷰를 리로드 해줍니다

 

 

상황 설명 : 냐옹을 지우니까 머리달린 닥트리오가 들어왔다

 

.....

 

우리 코드에서 앨범 데이터를 최신순으로 정렬하고 가장 최신 사진을 테이블뷰 셀에 보여주고 있었잖아요 ?

 

거기서 가장 최신 사진을 지우니까 그 이벤트를 감지한다면 다음 최신 사진이 셀에 나와야 할겁니다.

 

사진첩 데이터가 변화되고 PHPhotoLibraryChangeObserver 의 photoLibraryDidchange() 를 통해 변화의 결과를 받을 수 있습니다.

 

애플 공식 문서 PHPhotoLibraryChangeObserver 를 보시면 더 많은 정보를 보실 수 있어요 :)

 

 

 

참고 : https://www.edwith.org/boostcourse-ios/lecture/16867/

 

'iOS' 카테고리의 다른 글

[iOS] OperationQueue 톺아보기  (0) 2019.08.22
[iOS] 동시성, 비동기 프로그래밍 톺아보기  (0) 2019.08.21
[iOS] Codable 톺아보기  (0) 2019.08.01
[iOS] 세궈(Segue) 톺아보기  (1) 2019.08.01
[iOS] UITableView 톺아보기 - 3  (0) 2019.08.01
댓글
공지사항