PhotoKit 初体验

1.基类PHObject

Photos 框架中的根类PHObject只有一个公开接口 localIdentifier,是对象唯一标志符.PHObject实现了-isEqual-hash方法.可以直接使用localIdentifier属性对PHObject及其子类对象进行对比是否同一个对象

2.数据类型

PHAsset 、PHAssetCollection、PHCollectionList 是Photos框架中的模型类
PHAsset :代表系统的一个图片,视频或者Live Photo
PHAssetCollection:是一组有序的资源集合,包括相册、moments、智能相册以及共享照片流.比如:系统相册里的时刻一个分类,用户创建的相册或者智能相册
PHCollectionList : 相册集合, 比如:时刻里的年或者包含用户创建的一个或者多个相册
表示一组PHCollection,而它本身也是一个PHCollection,因此PHCollection作为一个集合,可以包含其他集合
如下资源结构图:


image.png

下面介绍下这些数据类型的一些属性和方法

2.1PHAsset
  • 1.mediaType:资源类型,图片或者音频或视频
 PHAssetMediaTypeUnknown = 0,
 PHAssetMediaTypeImage   = 1,
 PHAssetMediaTypeVideo   = 2,
 PHAssetMediaTypeAudio   = 3,
  • 2.mediaSubtypes:图片又包含全景图(Panorama)、HDR图片、屏幕截图、livePhoto .live photo 加3Dtouch效果 我们可以使用照片资源的 mediaSubtypes 属性验证资源库中的图像在捕捉时是否开启了 HDR,拍摄时是否使用了相机应用的全景模式
image.png
  • 3.pixelWidth:像素宽度

  • 4.pixelHeight 高度

  • 5.creationDate 创建时间

  • 6.modificationDate 修改时间

  • 7.location 位置信息

  • 8.duration时长

  • 9.hidden 要验证一个资源是否被用户标记为收被隐藏,只要检查 PHAsset 实例的 hidden 属性即可。

    1. Favorite 布尔值,用户是否标记资源为"收藏"
  • 11.representsBurst 和 burstSelectionTypes: 对于一个资源,如果其 PHAsset 的 representsBurst 属性为 true,则表示这个资源是一系列连拍照片中的代表照片 (多张照片是在用户按住快门时拍摄的)。它还有一个属性是 burstIdentifier,如果想要获取连拍照片中的剩余的其他照片,可以通过将这个值传入 fetchAssetsWithBurstIdentifier(...) 方法来获取。用户可以在连拍的照片中做标记;此外,系统也会自动用各种试探来标记用户可能会选择的潜在代表照片。这个元数据是可以通过 PHAsset 的 burstSelectionTypes 属性来访问。这个属性是用三个常量组成的位掩码:.UserPick 表示用户手动标记的资源,.AutoPick 表示用户可能标记的潜在资源,.None 表示没有标记的资源

  • 12.localIdentifier Photos 框架中的根类PHObject只有一个公开接口localIdentifier,是对象唯一唯一标志符.PHObject实现了-isEqual 和-hash方法.可以直接使用localIdentifier属性对PHObject及其子类对象进行对比是否同一个对象

  • 下面是一些方法

// 可执行编辑操作
 - (BOOL)canPerformEditOperation:(PHAssetEditOperation)editOperation;
常见的获取资源的方法
// 获取所有的资源  options是获取资源的条件下文介绍
+ (PHFetchResult<PHAsset *> *)fetchAssetsWithOptions:(nullable PHFetchOptions *)options;  
// 从相册中获取资源 , assetCollection 可以传入相册的对象
 + (PHFetchResult<PHAsset *> *)fetchAssetsInAssetCollection:(PHAssetCollection *)assetCollection options:(nullable PHFetchOptions *)options; 

2.2 PHCollection.h
2.2.1 PHCollection

PHAssetCollectionPHColletionList的父类

1、localizedTitle 相册的标题
// 获取资源的方法
+ (PHFetchResult<PHCollection *> *)fetchCollectionsInCollectionList:(PHCollectionList *)collectionList options:(nullable PHFetchOptions *)options;
2.2.2 PHAssetCollection 相册(PHAsset集合)
    1. assetCollectionType 指定资源集合类型来源,比如相册或者“时刻”相册
PHAssetCollectionTypeAlbum      = 1,      // 从 iTunes 同步来的相册,以及用户在 Photos 中自己建立的相册
 PHAssetCollectionTypeSmartAlbum = 2,  // 经由相机得来的相册
 PHAssetCollectionTypeMoment     = 3,     // 时刻”相册 Photos 为我们自动生成的时间分组的相册
    1. assetCollectionSubtype 子类型
typedef NS_ENUM(NSInteger, PHAssetCollectionSubtype) {
    
    // PHAssetCollectionTypeAlbum regular subtypes
    PHAssetCollectionSubtypeAlbumRegular         = 2, // 用户自己在Photos app中建立的相册
    PHAssetCollectionSubtypeAlbumSyncedEvent     = 3,// 已废弃;使用 iTunes 从 Photos 照片库或者 iPhoto 照片库同步过来的事件。然而,在iTunes 12 以及iOS 9.0 beta4上,选用该类型没法获取同步的事件相册,而必须使用AlbumSyncedAlbum。
    PHAssetCollectionSubtypeAlbumSyncedFaces     = 4, //使用 iTunes 从 Photos 照片库或者 iPhoto 照片库同步的人物相册。
    PHAssetCollectionSubtypeAlbumSyncedAlbum     = 5,// //从iPhoto同步到设备的相册
    PHAssetCollectionSubtypeAlbumImported        = 6,// 从相机或外部存储导入的相册
    
    // PHAssetCollectionTypeAlbum shared subtypes
    PHAssetCollectionSubtypeAlbumMyPhotoStream   = 100, //用户的 iCloud 照片流
    PHAssetCollectionSubtypeAlbumCloudShared     = 101,//用户使用iCloud共享的相册
    
    // PHAssetCollectionTypeSmartAlbum subtypes
    PHAssetCollectionSubtypeSmartAlbumGeneric    = 200,//非特殊类型的相册,从macOS Photos app同步过来的相册
    PHAssetCollectionSubtypeSmartAlbumPanoramas  = 201, //相机拍摄的全景照片
    PHAssetCollectionSubtypeSmartAlbumVideos     = 202,// 相机拍摄的视频
    PHAssetCollectionSubtypeSmartAlbumFavorites  = 203,// 收藏的照片、视频的相册
    PHAssetCollectionSubtypeSmartAlbumTimelapses = 204, // 延时视频的相册
    PHAssetCollectionSubtypeSmartAlbumAllHidden  = 205,// 包含隐藏照片、视频的相册
    PHAssetCollectionSubtypeSmartAlbumRecentlyAdded = 206,// 相机近期拍摄的照片、视频的相册
    PHAssetCollectionSubtypeSmartAlbumBursts     = 207, //连拍模式拍摄的照片
    PHAssetCollectionSubtypeSmartAlbumSlomoVideos = 208,// Slomo是slow motion的缩写,高速摄影慢动作解析(iOS设备以120帧拍摄)的相册
    PHAssetCollectionSubtypeSmartAlbumUserLibrary = 209,// 相机相册,包含相机拍摄的所有照片、视频,使用其他应用保存的照片、视频
    PHAssetCollectionSubtypeSmartAlbumSelfPortraits API_AVAILABLE(ios(9)) = 210,//包含了所有使用前置摄像头拍摄的资源的智能相册——自拍
    PHAssetCollectionSubtypeSmartAlbumScreenshots API_AVAILABLE(ios(9)) = 211,// 包含了所有使用屏幕截图的资源的智能相册——屏幕快照
    PHAssetCollectionSubtypeSmartAlbumDepthEffect API_AVAILABLE(macos(10.13), ios(10.2), tvos(10.1)) = 212,// 包含了所有兼容设备上使用景深效果拍摄的资源的智能相册
    PHAssetCollectionSubtypeSmartAlbumLivePhotos API_AVAILABLE(macos(10.13), ios(10.3), tvos(10.2)) = 213,// 包含了所有Live Photo的智能相册——Live Photo
    PHAssetCollectionSubtypeSmartAlbumAnimated API_AVAILABLE(macos(10.15), ios(11), tvos(11)) = 214,//动态图片gif
    PHAssetCollectionSubtypeSmartAlbumLongExposures API_AVAILABLE(macos(10.15), ios(11), tvos(11)) = 215,//所有开启长曝光的实况图片
    PHAssetCollectionSubtypeSmartAlbumUnableToUpload API_AVAILABLE(macos(10.15), ios(13), tvos(13)) = 216,

    // Used for fetching, if you don't care about the exact subtype
    PHAssetCollectionSubtypeAny = NSIntegerMax  //包含所有类型
};

注意:获取指定类型的相册时,主类型和子类型要匹配,若不匹配则系统会按照any子类型处理;
对于moment类型,子类型使用any;
对于smartAlbum类型,子类型使用albumRegular比使用any多一个Recently Deleted(最近删除)的相册;

    1. startDate endDate 开始 结束时间
  • 3.estimatedAssetCount :估算的asset数量,不精确

    1. approximateLocation; 大概的位置
    1. localizedLocationNames; 位置地区的名字数组
2.2.3 PHCollectionList : 相册集合

表示一组PHCollection,而它本身也是一个PHCollection,因此PHCollection作为一个集合,可以包含其他集合

  • 1.collectionListType
typedef NS_ENUM(NSInteger, PHCollectionListType) {
    PHCollectionListTypeMomentList    = 1, // 包含了PHAssetCollectionTypeMoment类型的资源集合的列表
    PHCollectionListTypeFolder        = 2, // 包含了PHAssetCollectionTypeAlbum类型或PHAssetCollectionTypeSmartAlbum类型的资源集合的列表
    PHCollectionListTypeSmartFolder   = 3, // 同步到设备的智能文件夹的列表
} PHOTOS_ENUM_AVAILABLE_IOS_TVOS(8_0, 10_0);
  • 2.collectionListSubtype
typedef NS_ENUM(NSInteger, PHCollectionListSubtype) {
    // PHCollectionListTypeMomentList的子类型
    PHCollectionListSubtypeMomentListCluster    = 1, // 时刻
    PHCollectionListSubtypeMomentListYear       = 2, // 年度
    // PHCollectionListTypeFolder的子类型
    PHCollectionListSubtypeRegularFolder        = 100, // 包含了其他文件夹或者相簿的文件夹
    // PHCollectionListTypeSmartFolder的子类型
    PHCollectionListSubtypeSmartFolderEvents    = 200, // 包含了一个或多个从iPhone同步的事件的智能文件夹
    PHCollectionListSubtypeSmartFolderFaces     = 201, // 包含了一个或多个从iPhone同步的面孔(人物)的智能文件夹
    // 如果你不关心子类型是什么,则使用下面这个
    PHCollectionListSubtypeAny = NSIntegerMax
} PHOTOS_ENUM_AVAILABLE_IOS_TVOS(8_0, 10_0);
  • 3 . startDate endDate 开始 结束时间
2.3.4 获取模型数据

PHAsset 、PHCollection、PHCollectionList有一系列类方法可供我们访问资源的元数据

1, 比如PHAsset提供了一系列获取PHAsset对象的方法
 + fetchAssetsInAssetCollection:options:
 + fetchAssetsWithMediaType:options:
 + fetchAssetsWithLocalIdentifiers:options:
 + fetchKeyAssetsInAssetCollection:options:
 + fetchAssetsWithOptions:  //获取所有资源、具体看option 可以设置包含icloud
 + fetchAssetsWithBurstIdentifier:options:
 + fetchAssetsWithALAssetURLs:options:
 其中fetchAssetsInAssetCollection:options:方法可以获取资源集合中的所有asset对象。每个方法中的 PHFetchOptions参数,是获取asset对象的一些配置,我们可以设置获取asset的条件,比如获取哪种资源,如何分类。获取的时候,如果该参数为空,则使用系统的默认值,当我们调用如上所示方法获取时,可以直接传nil
 

3.搜索条件

3.1 PHFetchOptions

PHFetchOptions : option的集合,对asset对象进行 过滤,排序和管理

1、 predicate 做选择的约束条件。比如,只获取图片,不获取视频。指定 PHAssetMediaType为image.
 
 2、 sortDescriptors 可指定字段用来对获取结果进行排序
 
 3、 includeHiddenAssets 获取结果是否包括被隐藏的资源
 
4、 includeAllBurstAssets 获取结果是否包括连拍资源
 
 5、 includeAssetSourceTypes 资源的来源
 PHAssetSourceTypeNone
 PHAssetSourceTypeUserLibrary
 PHAssetSourceTypeCloudShared
 PHAssetSourceTypeiTunesSynced
 
6、fetchLimit  搜索结果的限制 ,0 表示无限制
 
7、 wantsIncrementalChangeDetails ,搜索结果细节变化

4.搜索结果 PHFetchResult

PHFetchResult: 类似数组,包含assets或者collections有序的一系列集合
特点:
同步快速获取结果,即使结果集很大,框架也能保证获取速度. 因为它不会一次性将所有结果放进内存,而是按需批量加载
可以用类似 NSArray 的接口来访问PHFetchResult结果内的集合
提供快速枚举的方法

  • (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void ()(ObjectType obj, NSUInteger idx, BOOL *stop))block;
    就算满足请求的照片库内容发生了改变,获取方法所返回的 PHFetchResult 对象是不会自动更新。在后面的小节中,我们会介绍如何对返回的 PHFetchResult 对象的改变进行观察并处理更新内容。
    可以借助 PHObjectChangeDetails 或 PHFetchResultChangeDetails 对象来观察这些变化

下面来获取下所有PHAsset资源

- (void)getAllAlbum{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        //获取 All Photos (所有照片相册)
        //按时间排序
        PHFetchOptions *options = [[PHFetchOptions alloc] init];
        options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]];
        PHFetchResult<PHAsset *> * assets = [PHAsset fetchAssetsWithOptions:options];
        CPAlbumModel * albumModel = [[CPAlbumModel alloc] init];
        [albumModel loadDataFromAsset:assets];
//        [self.assetCollectionList addObject:albumModel];
        dispatch_async(dispatch_get_main_queue(), ^{
            self.albumModel = albumModel;
            [self.albumCollectionView reloadData];
        });
    });
}

至此我们已经成功的获取了 asset 对象
接下来我们将我们获取的 PHAsset对象解析成我们需要 UIImage 对象
需要的类介绍:

5.PHImageManager

5.1 PHImageManager

在框架中是个单例对象,用[PHImageManager defaultManager]获取,它提供了加载图片和视频的方法,解析 PHAsset 资源

// 获取自定义大小的图片
- (PHImageRequestID)requestImageForAsset:(PHAsset *)asset targetSize:(CGSize)targetSize contentMode:(PHImageContentMode)contentMode options:(nullable PHImageRequestOptions *)options resultHandler:(void (^)(UIImage *__nullable result, NSDictionary *__nullable info))resultHandler;
官方注释翻译:
 如果获取的资源的宽高比不符合, contentMode 决定现实的大小
 PHImageContentModeAspectFit:  等比例适应
 PHImageContentModeAspectFill:  等比例缩放适应
 PHImageContentModeDefault = PHImageContentModeAspectFit  默认值
 [PHImageRequestOptions isSynchronous] returns NO (or options is nil), resultHandler 可能会请求多次
 deliveryMode = PHImageRequestOptionsDeliveryModeOpportunistic
 默认情况下,这些API是异步执行,但是我们可以通过options参数中的synchronous属性,设置为同步执行,这些方法会阻塞当前调用线程直到下载完成或者发生错误
 请求取消将不再返回 resultHandler

方法参数解读:
 asset:   需要解析的资源
 targetSize: 需要获取的图像的尺寸,如果输入的尺寸大于资源原图的尺寸,则只返回原图。需要注意在 PHImageManager 中,所有的尺寸都是用 Pixel 作为单位(Note that all sizes are in pixels),因此这里想要获得正确大小的图像,需要把输入的尺寸转换为 Pixel。如果需要返回原图尺寸,可以传入 PhotoKit 中预先定义好的常量?PHImageManagerMaximumSize,表示返回可选范围内的最大的尺寸,即原图尺寸
 contentMode: 图像的剪裁方式,控制照片应该以按比例缩放还是按比例填充的方式放到最终展示的容器内。注意如果 targetSize 传入PHImageManagerMaximumSize,则 contentMode 无论传入什么值都会被视为 PHImageContentModeDefault
 options: PHImageRequestOptions 的实例,可以控制的内容相当丰富,包括图像的质量、版本,也会有参数控制图像的剪裁
 resultHandler: 请求结束后被调用的 block,返回一个包含资源对于图像的 UIImage 和包含图像信息的一个 NSDictionary,在整个请求的周期中,这个 block 可能会被多次调用

// 获取原图数据
请求大图 ,回调只执行一次,deliveryMode直接被忽略,设置了PHImageRequestOptionsVersionCurrent 并且资源被调整过,则返回最大的图
- (PHImageRequestID)requestImageDataForAsset:(PHAsset *)asset options:(nullable PHImageRequestOptions *)options resultHandler:(void(^)(NSData *__nullable imageData, NSString *__nullable dataUTI, UIImageOrientation orientation, NSDictionary *__nullable info))resultHandler;
// 取消正在加载的数据线
- (void)cancelImageRequest:(PHImageRequestID)requestID;
5.2 获取图片资源的控制条件类 PHImageRequestOptions

PHImageRequestOptions中包含了一系列控制请求图像的属性
如果resizeMode所控制的剪裁结果有所冲突,PhotoKit 会以 resizeMode 的结果为准

1,  PHImageRequestOptionsVersion version:

 这个属性是指获取的图像是否需要包含系统相册“编辑”功能处理过的信息(如滤镜,旋转等)
 图片编辑extension,可以根据次枚举获取原图或者是经编辑过的图片
 PHImageRequestOptionsVersionCurrent = 0, //当前的(编辑过?经过编辑的图:原图)
 PHImageRequestOptionsVersionUnadjusted, //经过编辑的图
 PHImageRequestOptionsVersionOriginal       //原始图片
 
 
 2, PHImageRequestOptionsDeliveryMode deliveryMode:
 则用于控制请求的图片质量
 PHImageRequestOptionsDeliveryModeOpportunistic:在速度与质量中均衡 根据我options.synchronous判断返回结果是一个或多个
 PHImageRequestOptionsDeliveryModeHighQualityFormat 制定的同步返回一个结果,返回的图片质量是比我们设定的size会好一点(实际上与PHImageRequestOptions的resizeMode枚举相关) 高质量图
 PHImageRequestOptionsDeliveryModeFastFormat 仅返回一次,效率较高之余获得的图质量不太好,速度最快
 
 3, PHImageRequestOptionsResizeMode resizeMode:  PHImageRequestOptionsResizeModeNone (or no resize)无效 属性控制图像的剪裁
  
 4 CGRect normalizedCropRect: 用于对原始尺寸的图像进行裁剪,基于比例坐标。只在 resizeMode 为 Exact 时有效
 5 BOOL networkAccessAllowed; 是否允许从 icloud请求资源 另一个和 iCloud 相关的属性是 progressHandler。你可以将它设为一个PHAssetImageProgressHandler 的 block,当从 iCloud 下载照片时,它就会被图像管理器自动调用
 6 BOOL synchronous 是否为同步操作,默认为NO,如果设置为YES则,相关模式下只会返回一张图片
  PHAssetImageProgressHandler progressHandler 当图像需要从 iCloud 下载时,这个 block 会被自动调用,block 中会返回图像下载的进度,图像的信息,出错信息。开发者可以利用这些信息反馈给用户当前图像的下载进度以及状况,但需要注意?progressHandler 不在主线程上执行,因此在其中需要操作 UI,则需要手工放到主线程执行
 上面有提到,requestImageForAsset 中的参数?resultHandler 可能会被多次调用,这种情况就是图像需要从 iCloud 中下载的情况。在?requestImageForAsset 返回的内容中,一开始的那一次请求中会返回一个小尺寸的图像版本,当高清图像还在下载时,开发者可以首先给用户展示这个低清的图像版本,然后 block 在多次调用后,最终会返回高清的原图。至于当前返回的图像是哪个版本的图像,可以通过 block 返回的 NSDictionary info 中获知,PHImageResultIsDegradedKey 表示当前返回的 UIImage 是低清图。如果需要判断是否已经获得高清图,可以这样判断:
 BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
7. progressHandler 网络进度
 requestImageForAsset 发出对图像的请求时,如果在同一个 PHImageManager 中同时对同一个资源发出图像请求,请求的进度是可以共享的,因此我们可以利用这个特性,把 PHImageManager 以单例的形式使用,这样在切换界面时也不用担心无法传递图像的下载进度。例如,在图像的列表页面触发了下载图像,当我们离开列表页面进入预览大图界面时,并不用担心会重新图像会重新下载,只要没有手工取消图像下载,进入预览大图界面下载图像会自动继续从上次的进度下载图像
 

  1. synchronous = YES. 同步。只返回一张图片并且deliveryMode会忽略用户设置的值,直接设为 PHImageRequestOptionsDeliveryModeHighQualityFormat。
            a. resizeMode: PHImageRequestOptionsResizeModeNone: 返回的是原图大小
            b. resizeMode: PHImageRequestOptionsResizeModeFast: 当原图是压缩图时,会使用targetSize来最优解码图片,获得的图片大小可能比targetSize大
            c. resizeMode: PHImageRequestOptionsResizeModeExact: 解压和Fast一样,但是返回的是指定targetSize的高质量图
         
         
  2. synchronous: NO. 异步。
            a. deliveryMode: PHImageRequestOptionsDeliveryModeOpportunistic: 会返回多张图片
                1). PHImageRequestOptionsResizeModeNone: 先返回低清的缩略图,再返回原图大小
                2). PHImageRequestOptionsResizeModeFast: 先返回低清的缩略图,再返回的图片如 1-b 一样
                3). PHImageRequestOptionsResizeModeExact: 先返回低清的缩略图,再返回的图片如 1-c一样
         
            b. deliveryMode: PHImageRequestOptionsDeliveryModeHighQualityFormat: 只会返回一张高清图片
                1). PHImageRequestOptionsResizeModeNone: 如 1-a 一样
                2). PHImageRequestOptionsResizeModeFast: 如 1-b 一样
                3). PHImageRequestOptionsResizeModeExact: 如 1-c一样
         
            c. deliveryMode: PHImageRequestOptionsDeliveryModeFastFormat: 只会返回一张图片,并且可能是低清图
                1). PHImageRequestOptionsResizeModeNone: 返回一张低清图
                2). PHImageRequestOptionsResizeModeFast: 返回一张低清图
                3). PHImageRequestOptionsResizeModeExact: 返回一张低清图

同类型的还有livePhoto筛选类 PHLivePhotoRequestOptionsvideo筛选类 PHVideoRequestOptions

5.3 livePhoto筛选类 PHLivePhotoRequestOptions
 PHImageRequestOptionsVersion version;
  PHImageRequestOptionsDeliveryMode deliveryMode;
  BOOL networkAccessAllowed; 
  PHAssetImageProgressHandler progressHandler;// 网络加载的进度
5.4 video筛选类 PHVideoRequestOptions
BOOL networkAccessAllowed;
PHVideoRequestOptionsVersion version;
 PHVideoRequestOptionsDeliveryMode deliveryMode;
 PHAssetVideoProgressHandler progressHandler;  // 网络进度
 
 // 获取视频
 - (PHImageRequestID)requestPlayerItemForVideo:(PHAsset *)asset options:(nullable PHVideoRequestOptions *)options resultHandler:(void (^)(AVPlayerItem *__nullable playerItem, NSDictionary *__nullable info))resultHandler;
 // 导出视频方法
 - (PHImageRequestID)requestAVAssetForVideo:(PHAsset *)asset options:(nullable PHVideoRequestOptions *)options resultHandler:(void (^)(AVAsset *__nullable asset, AVAudioMix *__nullable audioMix, NSDictionary *__nullable info))resultHandler;
 

6. PHPhotoLibrary

系统中PHPhotoLibrary单例对象 是用来维护用户照片库。当我们需要编辑资源对象元数据、资源内容、或者插入新的资源对象等,都可以借助通过PHPhotoLibrary单例对象执行block,block中创建我们指定的请求对象(比如PHAssetChangeRequest,PHAssetCollectionChangeRequest, PHCollectionListChangeRequest的对象)。photoLibraryDidChange(changeInfo: PHChange!)中进行

  • 授权状态
 PHAuthorizationStatusNotDetermined = 0, // 未选择
 PHAuthorizationStatusRestricted,        // 用户受到某些限制,不能自己决定,比如:家长控制
 PHAuthorizationStatusDenied,            // 用户明确拒绝
 PHAuthorizationStatusAuthorized         // 已经授权
// 协议 :
 PHPhotoLibraryChangeObserver:
 PHPhotoLibraryChangeObserver 协议能让我们知道照片相册库中的改变。Photos会发送系统图片改变的消息,我们可以遵守PHPhotoLibraryChangeObserver协议,并通过 PHPhotoLibrary的registerChangeObserver方法将对象注册为观察者,时时接收照片改变的消息。
 // 串行队列 相册数据改变 知道照片相册库中的改变
 - (void)photoLibraryDidChange:(PHChange *)changeInstance;
 
 // 单利初始化
 + (PHPhotoLibrary *)sharedPhotoLibrary;
 //判断授权
 + (PHAuthorizationStatus)authorizationStatus;
 请求授权
 + (void)requestAuthorization:(void(^)(PHAuthorizationStatus status))handler;

 //  执行同步和异步数据
 - (void)performChanges:(dispatch_block_t)changeBlock completionHandler:(nullable void(^)(BOOL success, NSError *__nullable error))completionHandler;
 - (BOOL)performChangesAndWait:(dispatch_block_t)changeBlock error:(NSError *__autoreleasing *)error;
 
 // 将对象注册为观察者,时时接收照片改变的消息。
 - (void)registerChangeObserver:(id<PHPhotoLibraryChangeObserver>)observer;
 - (void)unregisterChangeObserver:(id<PHPhotoLibraryChangeObserver>)observer;

授权在项目中的使用

/**权限校验*/
- (void)authorization{
    if ([PHPhotoLibrary authorizationStatus] == PHAuthorizationStatusAuthorized){//用户之前已经授权
           //获取所有图片的相册
           [self getAllAlbum];
       }else if([PHPhotoLibrary authorizationStatus] == PHAuthorizationStatusDenied){//用户之前已经拒绝授权
           UIAlertController *alertC = [UIAlertController alertControllerWithTitle:@"提示" message:@"您之前拒绝了访问相册,请到手机隐私设置" preferredStyle:UIAlertControllerStyleAlert];
           UIAlertAction *sureAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
               [self dismissViewControllerAnimated:YES completion:nil];
           }];
           [alertC addAction:sureAction];
           [self presentViewController:alertC animated:YES completion:nil];
       }else{//弹窗授权时监听
           __weak typeof(self) weakself = self;
           [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
               if (status == PHAuthorizationStatusAuthorized){//允许
                   [weakself getAllAlbum];//获取数据 刷新视图
               }else{//拒绝
                    DLog(@"用户拒绝访问相册");
               }
           }];
       }
}

7.一些常用的使用和问题

7.1 监听相册的变化

我这边实现的功能是单外部应用对相册进行添加活删除,自己app 同步更新
第一步、注册监听

    //监听相册变化
    [[PHPhotoLibrary sharedPhotoLibrary] registerChangeObserver:self];

第二步、实现代理方法

#pragma mark — PHPhotoLibraryChangeObserver
- (void)photoLibraryDidChange:(PHChange *)changeInstance{
    PHFetchResultChangeDetails *changeDetial = [changeInstance changeDetailsForFetchResult:self.albumModel.assets];
    PHFetchResult<PHAsset *> * results = [changeDetial fetchResultAfterChanges];//获得更新之后的数据
    if(!changeDetial || !results) return;//有些时候可能活返回nil 过滤掉
    dispatch_async(dispatch_get_main_queue(), ^{
        if (results.count != self.albumModel.assets.count) {
             [self.albumModel loadDataFromAsset:results];
             [self.albumCollectionView reloadData];
        }
    });
}

第三步、记得注销观察者

-(void)dealloc{
    [[PHPhotoLibrary sharedPhotoLibrary] unregisterChangeObserver:self];
}
7.2 gif图片问题

项目中用到上传图片,遇到gif 图片要获取图片原数据,刚开始是采用下面的方式去获取

    [[PHCachingImageManager defaultManager] 
      requestImageDataForAsset:self.asset 
      options:options 
      resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
     
    }];

但是发现imageData的大小比原来的gif 文件小。获取到的只是gif 的一帧。
后面改成了下面的这种方法

 PHAssetResource *resource = [PHAssetResource assetResourcesForAsset:asset].firstObject;
    PHAssetResourceRequestOptions *resOptions = [[PHAssetResourceRequestOptions alloc] init];
    resOptions.networkAccessAllowed = YES;
    NSMutableData * mData = [NSMutableData data];
    @autoreleasepool {
        [[PHAssetResourceManager defaultManager] requestDataForAssetResource:resource options:resOptions dataReceivedHandler:^(NSData * _Nonnull data) {
               [mData appendData:data];
           } completionHandler:^(NSError * _Nullable error) {
               dispatch_async(dispatch_get_main_queue(), ^{
                   if (!error) {
                       if(success) success(mData);
                   }else{
                       if(failure) failure(error);
                   }
               });
           }];
    }

这种方式获取到的资源大小就是和原来的大小是一致的

参考文章

iOS PhotoKit 初用
Photokit 仿微信实现多图选择(上)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349