常用類介紹
-
PHPhotoLibrary:該類用於表示設備和iCloud上所有的收藏和資源。可以使用一個共享實例以一種線程安全的方法對照片庫的變化進行管理,比如添加新的資源和相簿,或者編輯和刪除已有的資源或相簿,此外,共享實例還可以註冊一個關於照片庫發生變化的監聽對象,以實現用戶界面的同步。
-
PHAssetCollection:該類一般用於表示一組照片或者視頻》可以在設備上本地創建,可以從iPhone中同步照片,可以從相冊或保存照片的相簿中獲取圖片,或者從根據一定的約束條件得到的智能相簿中(比如全景照片)同步圖片。該類還提供以組的方式訪問資源。資源集合可以以集合列表的方式進行組合。
-
PHAsset:該類用於表示照片或者視頻的元數據。它提供了一些類方法,返回使用了相同約束條件的資源結果,提供帶資源信息的實例方法,比如日期,位置,類型,和方向之類的信息。
-
PHFetchResult:這是一個輕量級的對象,用於表示一組資源或者資源集合。當按照約束條件請求資源或者資源集合時m,類方法將會返回一個抓取結構(fetch result)。抓取結果會按照需求載入資源 而不是一次將所有資源載入內存,這樣即使面對大資源也能很好的加以處理,抓取結果同時還是線程安全的,這意味着如果底層數據發生變化,對象的個數不會變。可以爲照片庫的變化註冊一個請求通知類,這樣變化通過PHFetchResultChangeDetails 實例發送,可以用於更新抓取結果和所有的相應的用戶界面
-
PHImageManager:圖片管理器以異步的方式處理圖片數據的抓取和保存,尤其適用於獲取指定尺寸的圖片或者管理從iCloud獲取的圖片數據。此外,當需要在表現圖或者集合視圖中顯示大量資源時m,照片庫還提供PHCachingImageManager 類來提升視圖滑動的流暢度。
PHAssetCollectionType 和PHAssetCollectionSubtype 介紹
public enum PHAssetCollectionType : Int {
case album /// 自己創建的相冊
case smartAlbum /// 經由系統相機得來的相冊
case moment /// 自動生成的時間分組的相冊
}
public enum PHAssetCollectionSubtype : Int {
// PHAssetCollectionTypeAlbum regular subtypes
case albumRegular // 在iPhone中自己創建的相冊
case albumSyncedEvent // 從iPhoto(就是現在的圖片app)中導入圖片到設備
case albumSyncedFaces // 從圖片app中導入的人物照片
case albumSyncedAlbum // 從圖片app導入的相冊
case albumImported // 從其他的相機或者存儲設備導入的相冊
// PHAssetCollectionTypeAlbum shared subtypes
case albumMyPhotoStream // 照片流,照片流和iCloud有關,如果在設置裏關閉了iCloud開關,就獲取不到了
case albumCloudShared // iCloud的共享相冊,點擊照片上的共享tab創建後就能拿到了,但是前提是你要在設置中打開iCloud的共享開關(打開後才能看見共享tab)
// PHAssetCollectionTypeSmartAlbum subtypes
case smartAlbumGeneric //一般的照片
case smartAlbumPanoramas // 全景圖、全景照片
case smartAlbumVideos // 視頻
case smartAlbumFavorites // 標記爲喜歡、收藏
case smartAlbumTimelapses // 延時拍攝、定時拍攝
case smartAlbumAllHidden // 隱藏的
case smartAlbumRecentlyAdded // 最近添加的、近期添加
case smartAlbumBursts // 連拍
case smartAlbumSlomoVideos // 慢動作視頻
case smartAlbumUserLibrary // 相機膠捲
@available(iOS 9.0, *)
case smartAlbumSelfPortraits // 使用前置攝像頭拍攝的作品
@available(iOS 9.0, *)
case smartAlbumScreenshots // 屏幕截圖
@available(iOS 10.2, *)
case smartAlbumDepthEffect // 使用深度攝像模式拍的照片
@available(iOS 10.3, *)
case smartAlbumLivePhotos //Live Photo資源
@available(iOS 11.0, *)
case smartAlbumAnimated
@available(iOS 11.0, *)
case smartAlbumLongExposures
// Used for fetching, if you don't care about the exact subtype
case any
}
請求相冊和相機權限
/*使用說明
需要在Info.plist 中添加
Privacy - Photo Library Additions Usage Description 添加圖片
Privacy - Photo Library Usage Description 讀取圖片*/
import Foundation
import Photos
import AVFoundation
public enum PhotoAuthorizationStatus:String{
case photoNotDetermined = "用戶尚未對相冊權限做出選擇"
case photoRestricted = "用戶無權訪問相冊"
case photoDenied = "用戶拒絕訪問相冊"
case photoAuthorized = "用戶允許訪問相冊"
}
public enum CameraAuthorizationStatus:String{
case cameraNotDetermined = "用戶尚未對相機權限做出選擇"
case cameraRestricted = "用戶無權訪問相機"
case cameraDenied = "用戶拒絕訪問相機"
case cameraAuthorized = "用戶允許訪問相機"
}
struct AuthorizationManager{
public static var photoStatus:PhotoAuthorizationStatus{
let status = PHPhotoLibrary.authorizationStatus()
var photoStatus: PhotoAuthorizationStatus = .photoNotDetermined
switch status {
case .notDetermined:
photoStatus = .photoNotDetermined
case .restricted:
photoStatus = .photoRestricted
case .denied:
photoStatus = .photoDenied
case .authorized:
photoStatus = .photoAuthorized
@unknown default:
photoStatus = .photoNotDetermined
}
return photoStatus
}
public static var cameraStatus:CameraAuthorizationStatus{
let status = AVCaptureDevice.authorizationStatus(for: .video)
var cameraStatus: CameraAuthorizationStatus = .cameraNotDetermined
switch status {
case .notDetermined:
cameraStatus = .cameraNotDetermined
case .restricted:
cameraStatus = .cameraRestricted
case .denied:
cameraStatus = .cameraDenied
case .authorized:
cameraStatus = .cameraAuthorized
@unknown default:
cameraStatus = .cameraNotDetermined
}
return cameraStatus
}
public static func checkPhotoAuthorization(complition:@escaping (PhotoAuthorizationStatus)->Void){
if photoStatus == .photoAuthorized{
complition(.photoAuthorized)
}
requestPhotoAuthorization(complition: complition)
}
public static func requestPhotoAuthorization(complition:@escaping (PhotoAuthorizationStatus)->Void){
var photoStatus:PhotoAuthorizationStatus = .photoNotDetermined
PHPhotoLibrary.requestAuthorization { (status) in
switch status{
case .notDetermined:
photoStatus = .photoNotDetermined
case .restricted:
photoStatus = .photoRestricted
case .denied:
photoStatus = .photoDenied
case .authorized:
photoStatus = .photoAuthorized
@unknown default:
photoStatus = .photoNotDetermined
}
DispatchQueue.main.async {
complition(photoStatus)
}
}
}
public static func checkCameraAuthorization(complition:@escaping (CameraAuthorizationStatus)->Void){
if cameraStatus == .cameraAuthorized{
complition(.cameraAuthorized)
}
requestCameraAuthorization(complition: complition)
}
public static func requestCameraAuthorization(complition:@escaping (CameraAuthorizationStatus)->Void){
var cameraStatus: CameraAuthorizationStatus = .cameraNotDetermined
AVCaptureDevice.requestAccess(for: .video) { (isSuccess) in
if isSuccess{
cameraStatus = .cameraAuthorized
}else{
cameraStatus = .cameraDenied
}
DispatchQueue.main.async {
complition(cameraStatus)
}
}
}
}
獲取相冊的圖片
import UIKit
import Photos
open class LQPhotoManager:NSObject {
public weak var delegate:LQPhotoManagerDelegate?
public init(photoDelegate:LQPhotoManagerDelegate?){
delegate = photoDelegate
super.init()
PHPhotoLibrary.shared().register(self)
}
public func unregisterChangeObserver(){
PHPhotoLibrary.shared().unregisterChangeObserver(self)
}
public func requestPhotosData(){
AuthorizationManager.checkPhotoAuthorization { (status) in
self.notifyObserver(status: status)
}
}
}
/*
可以使用PHChnage下面的方法去監聽發生的變化
public func changeDetails<T>(for fetchResult: PHFetchResult<T>) -> PHFetchResultChangeDetails<T>? where T : PHObject
通過PHFetchResultChangeDetails的下面的發生的變化
//
open var fetchResultBeforeChanges: PHFetchResult<ObjectType> { get }
open var fetchResultAfterChanges: PHFetchResult<ObjectType> { get }
*/
public protocol LQPhotoManagerDelegate:AnyObject{
func photosDataDidChange(changeInstance: PHChange)
func photosAuthorizationChange(status:PhotoAuthorizationStatus)
}
extension LQPhotoManager{
/// 獲取相冊
///
/// - Parameters:
/// - type: 相冊類型
/// - subtype: 哪種類型拍攝的
/// - options: 篩選條件
public class func getAlbum(with type: PHAssetCollectionType, subtype: PHAssetCollectionSubtype, options: PHFetchOptions? = nil)-> PHFetchResult<PHAssetCollection>{
return PHAssetCollection.fetchAssetCollections(with: PHAssetCollectionType.album, subtype: PHAssetCollectionSubtype.any, options: options)
}
/// 創建相冊
///
/// - Parameter albumName: 相冊的名字
public class func createAlbum(albumName:String?) {
guard let name = albumName else{
return
}
PHPhotoLibrary.shared().performChanges({
PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: name)
}) { (success, error) in
if !success{
print("創建相冊失敗 錯誤信息:\(error?.localizedDescription ?? "沒有錯誤信息")")
}
}
}
/// 刪除多個相冊
///
/// - Parameter albumsToBeDeleted: [PHAssetCollection]?
public class func deleteAlbums(albumsToBeDeleted: [PHAssetCollection]?) {
guard let albums = albumsToBeDeleted else {
return
}
PHPhotoLibrary.shared().performChanges({
PHAssetCollectionChangeRequest.deleteAssetCollections(albums as NSFastEnumeration)
}) { (success, error) in
if !success{
print("刪除多個相冊失敗 錯誤信息:\(error?.localizedDescription ?? "沒有錯誤信息")")
}
}
}
/// 獲取相冊中的照片
///
/// - Parameter album: PHAssetCollection
/// - Returns: PHFetchResult<PHAsset>
public class func getPhotosFromAlbum(album:PHAssetCollection?) -> PHFetchResult<PHAsset>? {
guard let al = album else {
return nil
}
return PHAsset.fetchAssets(in: al, options: nil)
}
/// 將圖片加入相冊
///
/// - Parameters:
/// - image: UIImage
/// - toAlbum: PHAssetCollection
public class func addImage(image:UIImage?,toAlbum:PHAssetCollection?){
guard let img = image,let album = toAlbum else {
return
}
PHPhotoLibrary.shared().performChanges({
let addImageRequest = PHAssetChangeRequest.creationRequestForAsset(from: img)
let addedImagePlaceholder = addImageRequest.placeholderForCreatedAsset
let addImageToAlbum = PHAssetCollectionChangeRequest.init(for: album)
addImageToAlbum?.addAssets([addedImagePlaceholder] as NSFastEnumeration)
}) { (success, error) in
if !success{
print("將圖片加入相冊失敗 錯誤信息:\(error?.localizedDescription ?? "沒有錯誤信息")")
}
}
}
/// 將照片從相冊中刪除
///
/// - Parameter photoAssets: [PHAsset]
public class func deleteImagesFromAlbum(photoAssets:[PHAsset]?){
guard let photos = photoAssets else {
return
}
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.deleteAssets(photos as NSFastEnumeration)
}) { (success, error) in
if !success{
print("將圖片加入相冊失敗 錯誤信息:\(error?.localizedDescription ?? "沒有錯誤信息")")
}
}
}
/// 將PHAsset 轉成Image
///
/// - Parameters:
/// - photoAsset: PHAsset
/// - imageSize: 圖片尺寸
/// - contentMode: 拉伸模式
/// - resultHandler: 轉換成功後的回調
public class func changePHAssetToImage(photoAsset:PHAsset?,contentMode:PHImageContentMode = PHImageContentMode.aspectFill,resultHandler: @escaping (UIImage?, [AnyHashable : Any]?) -> Void) {
guard let photoA = photoAsset else {
return
}
let imageManager = PHImageManager.default()
imageManager.requestImage(for: photoA, targetSize: CGSize.init(width: photoA.pixelWidth, height: photoA.pixelHeight), contentMode: contentMode, options: nil) { (image, imageInfo) in
resultHandler(image,imageInfo)
}
}
internal func notifyObserver(status:PhotoAuthorizationStatus){
DispatchQueue.main.async {
self.delegate?.photosAuthorizationChange(status: status)
}
}
}
extension LQPhotoManager:PHPhotoLibraryChangeObserver{
public func photoLibraryDidChange(_ changeInstance: PHChange) {
DispatchQueue.main.async {
self.delegate?.photosDataDidChange(changeInstance: changeInstance)
}
}
}