Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- Observable
- swiftUI
- ribs
- RxCocoa
- clean architecture
- 애니메이션
- UICollectionView
- ios
- Xcode
- 리펙터링
- uiscrollview
- Clean Code
- tableView
- Protocol
- combine
- map
- SWIFT
- Refactoring
- uitableview
- 리펙토링
- rxswift
- 스위프트
- swift documentation
- 리팩토링
- 클린 코드
- UITextView
- HIG
- MVVM
- collectionview
- Human interface guide
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] 1. 갤러리 화면 만들기, 사진 첨부 - 앨범 가져오기 (PHFetchResult, PHAsset) 본문
UI 컴포넌트 (swift)
[iOS - swift] 1. 갤러리 화면 만들기, 사진 첨부 - 앨범 가져오기 (PHFetchResult, PHAsset)
jake-kim 2023. 6. 27. 01:501. 갤러리 화면 만들기, 사진 첨부 - 앨범 가져오기 (PHFetchResult, PHAsset)
2. 갤러리 화면 만들기, 사진 첨부 - 사진 가져오기 (PHCachingImageManager, PHImageRequestOptions)
3. 갤러리 화면 만들기, 사진 첨부 - 갤러리 화면 UI 구현 방법
앨범과 사진 가져오는 방법
- Photos 모듈에서 제공하는 API를 사용
- 디바이스의 앨범을 먼저 가져오기 (PHFetchResult가 앨범을 의미)
- 앨범에 담긴 이미지 정보 가져오기 (PHAsset이 이미지나 비디오 정보를 의미)
- PHAsset을 가지고 UIImage 이미지 가져오기 (PHCachingImageManager가 요청한 크기에 맞추어 PHAsset으로부터 이미지를 가져옴)
- 쿼리는 모두 PHImageRequestOptions를 작성
- 위에서 얻은 이미지(UIImage)를 UICollectionView와 UICollectionViewFlowLayout으로 쉽게 구현이 가능
예제에 사용한 라이브러리
- Cocoapod 사용
- Then: sugar 프로그래밍에 도움을 주는 라이브러리
- SnapKit: 코드베이스로 오토레이아웃을 쉽게 적용하기 위한 라이브러리
pod 'Then'
pod 'SnapKit'
사진 접근 권한 요청
- 공용적으로 사용될 수 있으므로 별도의 Service 레이어에서 구현
(권한 요청은 갤러리에서 사진 선택 화면의 메인 기능이 아니므로 구현체는 생략)
- 버튼을 누르면 requestAuthorization(completion:)이 호출되도록 구현
protocol PhotoAuthService {
var authorizationStatus: PHAuthorizationStatus { get }
var isAuthorizationLimited: Bool { get }
func requestAuthorization(completion: @escaping (Result<Void, NSError>) -> Void)
}
앨범 가져오기 (PHFertchResult)
- 앨범 가져오기 역시 여러곳에서 사용될 수 있으므로 AlbumService라는 레이어로 분리하여 기능을 구현
import Photos
import UIKit
import Then
protocol AlbumService {
func getAlbums(mediaType: MediaType, completion: @escaping ([AlbumInfo]) -> Void)
}
- 쿼리 NSFetchOptions에 사용될 헬퍼 property와 mediaType을 쿼리에 사용될 메소드미리 정의
final class MyAlbumService: AlbumService {
private let getSortDescriptors = [
NSSortDescriptor(key: "creationDate", ascending: false),
NSSortDescriptor(key: "modificationDate", ascending: false)
]
private func getPredicate(mediaType: MediaType) -> NSPredicate {
let format = "mediaType == %d"
switch mediaType {
case .all:
return .init(
format: format + " || " + format,
PHAssetMediaType.image.rawValue,
PHAssetMediaType.video.rawValue
)
case .image:
return .init(
format: format,
PHAssetMediaType.image.rawValue
)
case .video:
return .init(
format: format,
PHAssetMediaType.video.rawValue
)
}
}
}
- 앨범 가져오는 방법
- 0. albums 변수 선언
- 1. query 설정
- 2. standard 앨범을 query로 이미지 가져오기
- 3. smart 앨범을 query로 이미지 가져오기
- 0. albums 변수 선언
- 쿼리를 날려서 앨범을 가져오는데, 이때 가져올 앨범들이 저장될 변수
final class MyAlbumService: AlbumService {
func getAlbums(mediaType: MediaType, completion: @escaping ([AlbumInfo]) -> Void) {
// 0. albums 변수 선언
var albums = [AlbumInfo]()
defer { completion(albums) }
// 1. query 설정
// 2. standard 앨범을 query로 이미지 가져오기
// 3. smart 앨범을 query로 이미지 가져오기
}
}
- 1. query 설정
- PHFetchOptions()를 사용하여 쿼리 날리기
// 1. query 설정
let fetchOptions = PHFetchOptions().then {
$0.predicate = getPredicate(mediaType: mediaType)
$0.sortDescriptors = getSortDescriptors
}
- 2. standard 앨범을 query로 이미지 가져오기
- PHAsset.fetchAsset(with:)을 사용하여 일반 앨범 가져오기
// 2. standard 앨범을 query로 이미지 가져오기
let standardFetchResult = PHAsset.fetchAssets(with: fetchOptions)
albums.append(.init(fetchResult: standardFetchResult, albumName: mediaType.title))
- 3. smart 앨범을 query로 이미지 가져오기
- PHAssetCollection을 사용하여 스마트 앨범을 가져오기
- 나머지 스마트 앨범은 estimatedAssetCount의 값이 -1인 경우 (NSNotFount) 추가로 가져오는 코드도 필요
// 3. smart 앨범을 query로 이미지 가져오기
let smartAlbums = PHAssetCollection.fetchAssetCollections(
with: .smartAlbum,
subtype: .any,
options: PHFetchOptions()
)
smartAlbums.enumerateObjects { [weak self] phAssetCollection, index, pointer in
guard let self, index <= smartAlbums.count - 1 else {
pointer.pointee = true
return
}
// 스마트 앨범인 경우 (Asset count가 -1인 경우)
if phAssetCollection.estimatedAssetCount == NSNotFound {
let fetchOptions = PHFetchOptions().then {
$0.predicate = self.getPredicate(mediaType: mediaType)
$0.sortDescriptors = self.getSortDescriptors
}
let fetchResult = PHAsset.fetchAssets(in: phAssetCollection, options: fetchOptions)
albums.append(.init(fetchResult: fetchResult, albumName: mediaType.title))
}
}
앨범 가져오는걸 사용하는 쪽
- PhotoViewController라는 곳의 viewDidLoad에서 아래처럼 호출하여 사용
- 위에서 살펴본 앨범을 가져오는 기능을 사용하여 앨범들을 가져오고, 그 앨범들에서 [PHAsset]를 불러오는 것
- PHAsset정보가 있으면 UIImage를 가져올 수 있으므로 UI에 이 UIImage를 그리도록하면 완성
// PhotoViewController.swift
private let albumService: AlbumService = MyAlbumService()
private var albums = [PHFetchResult<PHAsset>]()
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
loadAlbums(completion: { [weak self] in
self?.loadImages()
})
}
private func loadAlbums(completion: @escaping () -> Void) {
albumService.getAlbums(mediaType: .image) { [weak self] albumInfos in
self?.albums = albumInfos.map(\.album)
completion()
}
}
private func loadPHAssetsFromAlbums() {
// TODO...
}
(가져온 앨범을 토대로 사진을 가져오고 UI에 그리는 방법은 다음 포스팅 글에서 계속)
'UI 컴포넌트 (swift)' 카테고리의 다른 글
Comments