티스토리 뷰
안녕하세요 :) Zedd입니다.
오늘은 iOS 14이상 && 사진앨범에 접근할 때
사진 선택옵션이 추가되었습니다. 관련 대응을 기록하고자 합니다.
현재 글과 다음 글 총 2편으로 이루어져있습니다. 최종 코드는 github에 올려놨습니다.
예제 프로젝트 입니다.
우상단 Add버튼을 누른 뒤, 만약 모든 사진에 대해 허용을 누르면,
내 모든 사진을 가져와 collectionView에 뿌려주는 간단한 앱입니다.
하지만 iOS14에서는 Select Photos를 통해 내가 선택한 사진에만 접근 할 수 있도록 할 수 있습니다.
이렇게요. 같이해보겠습니다.
먼저 권한 요청부터 해주겠습니다.
# 권한 요청.
iOS 14 이전.
iOS 14 이후
참고로
이 파라미터에는 PHAccessLevel타입이 들어갈 수 있습니다.
@available(iOS 14, iOS 8, *)
public enum PHAccessLevel : Int {
@available(iOS 8, *)
case addOnly = 1
@available(iOS 8, *)
case readWrite = 2
}
PHAccessLevel은 enum으로, addOnly와 readWrite가 있습닏니다.
⚠️ 주의하셔야 할 점은, addOnly시에는
이 alert이 뜨고 Select Photos를 눌러도!!!!!!!!! PHPicker가 안뜹니다.
readWrite를 넘겨줘야 PHPicker가 뜨더라구요.
(이건 왜그런지 정확한 이유를 모르겠습니다. read권한이 없어서 인건가?)
아무튼 코드에서 보실 수 있다시피,
PHPhotoLibrary.requestAuthorization(for: .readWrite) { authorizationStatus in
switch authorizationStatus {
case .limited:
print("limited authorization granted") // 선택한 사진에 대해서만 허용.
case .authorized:
print("authorization granted") // 모든 권한 허용.
default:
print("Unimplemented")
}
}
limited case가 선택한 사진에 대해서만 권한을 허용하겠다~ 라는 뜻입니다.
# 권한 선택 후 작업
권한 요청이 비동기로 이루어지기 때문에..completion으로 작업해주겠습니다.
# 원하는 곳에서 호출
앱 실행 후 Add 버튼을 누르면,
여기까지 할 수 있게 됩니다.
주의하실 점은,
권한 요청 alert에서 모든 사진에 대 허용을 누를 때 처럼, Select Photos를 호출하는 순간
switch authorizationStatus {
case .limited:
completion()
print("limited authorization granted")
}
이게 호출되는게 아닙니다.
PHPicker가 나오고, 내가 Done을 누르면!!!
그제서야 "limited authorization granted"이 콘솔에 찍히게 됩니다.
# fetchAssets
핵심은, "내가 선택한 이미지에만 접근을 허용한다"입니다.
내가 Done을 누르면 모든 이미지가 아니라, 내가 선택한 이미지만 나와야하죠.
(모두 나오게 하려고 해도 안나옴)
참고로 아래 코드 말고 다양한 방법이 있을 수 있습니다.
핵심 코드인데요. 한줄씩 보겠습니다.
1. 모든 asset호출.
var fetchResult: PHFetchResult<PHAsset>?
self.fetchResult = PHAsset.fetchAssets(with: nil)
먼저 모든 asset을 불러와줍니다.
근데 이게 디바이스 / 시뮬레이터 동작이 다릅니다.
디바이스
var fetchResult: PHFetchResult<PHAsset>?
self.fetchResult = PHAsset.fetchAssets(with: nil)
사진첩에 사진이 7개가 있음 -> 내가 사진을 3개 선택함 -> fetchResult의 count값 : 3
시뮬레이터
var fetchResult: PHFetchResult<PHAsset>?
self.fetchResult = PHAsset.fetchAssets(with: nil)
사진첩에 사진이 7개가 있음 -> 내가 사진을 3개 선택함 -> fetchResult의 count값 : 7
그래서 디바이스로 돌리는 것을 추천드립니다.
2. 위에서 불러온 asset들을 탐색하면서 image를 가져온다.
func getCanAccessImages() {
self.canAccessImages = []
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true
let fetchOptions = PHFetchOptions()
self.fetchResult = PHAsset.fetchAssets(with: fetchOptions)
self.fetchResult.enumerateObjects { (asset, _, _) in
PHImageManager().requestImage(for: asset, targetSize: self.thumbnailSize, contentMode: .aspectFill, options: requestOptions) { (image, info) in
guard let image = image else { return }
self.canAccessImages.append(image)
DispatchQueue.main.async {
self.collectionView.insertItems(at: [IndexPath(item: self.canAccessImages.count - 1, section: 0)])
}
}
}
}
fetchResult를 돌면서 image를 요청합니다. targetSize와 contentMode는 알아서들 해주시고..
resultHandler로 image가 반환됩니다.
collectionView에 표시해줘야하니...canAccessImages라는 배열에 image를 넣어줬습니다.
그리고 동시에 collectionView에 insert해줬습니다.
(reload 하구싶었는데, 타이밍이 애매해서 insert로 처리..)
2-1 두번째 방법 ⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️
func getCanAccessImages() {
self.canAccessImages = []
let fetchOptions = PHFetchOptions() // 안줘도됨
self.fetchResult = PHAsset.fetchAssets(with: fetchOptions)
DispatchQueue.main.async {
self.collectionView.reloadData()
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.fetchResult.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCollectionViewCell", for: indexPath) as! ImageCollectionViewCell
let asset = self.fetchResult[indexPath.item]
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true
PHImageManager().requestImage(for: asset, targetSize: self.thumbnailSize, contentMode: .aspectFill, options: requestOptions) { (image, _) in
cell.imageView.image = image
}
return cell
}
자...이러면 requestImage를 cell쪽에서 해도 됩니다;;;
2-1 두번째 방법은..위에서 말했듯이
내가 선택한 사진 개수와 상관없이 fetchResult.count == 내 모든 asset count
&&
내가 선택 안한 사진은 image를 못불러옴
때문에
이런 현상이 나타납니다. 디바이스에서는 안그러니까 참고하세요. 이 글과 다음 글은 2-1방법이 아닌
func getCanAccessImages() {
self.canAccessImages = []
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true
let fetchOptions = PHFetchOptions()
self.fetchResult = PHAsset.fetchAssets(with: fetchOptions)
self.fetchResult.enumerateObjects { (asset, _, _) in
PHImageManager().requestImage(for: asset, targetSize: self.thumbnailSize, contentMode: .aspectFill, options: requestOptions) { (image, info) in
guard let image = image else { return }
self.canAccessImages.append(image)
DispatchQueue.main.async {
self.collectionView.insertItems(at: [IndexPath(item: self.canAccessImages.count - 1, section: 0)])
}
}
}
}
이 코드로 설명하겠습니다. (디바이스 / 시뮬레이터 둘 다 잘나오는 코드)
이렇게 됩니다.
iOS 14+ ) Select Photos 권한 작업 (2) 읽으러가기
'iOS' 카테고리의 다른 글
iOS ) 현재 IP 주소 가져오기. (2) | 2020.09.22 |
---|---|
iOS 14+ ) Select Photos 권한 작업 (2) (3) | 2020.09.20 |
iOS ) PHImageManager의 requestImage가 두번 호출되는 이슈. (0) | 2020.09.20 |
Configuring the Back Button (3) | 2020.09.13 |
iOS 14 + ) UILabel - lineBreakStrategy 실험👀 (2) | 2020.08.18 |
- github
- Combine
- 회고
- actor
- iOS delegate
- fastlane
- swift3
- Git
- swift delegate
- SwiftUI
- WidgetKit
- Xcode
- WKWebView
- 스위프트 문법
- ios 13
- 피아노
- 스위프트
- IOS
- np-hard
- swift sort
- Accessibility
- swift array
- swift tutorial
- UIBezierPath
- swift 공부
- Swift
- WWDC
- FLUTTER
- 제이슨 파싱
- np-complete
- Total
- Today
- Yesterday