티스토리 뷰
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 |