PHPhotoLibrary
- 父类:NSObject
一个共享对象(即单例,因为苹果爸爸的官方文档里面是这个词,这里不做更改),用来管理访问以及修改用户的相册库。
一、概述
这个共享的PHPhotoLibrary
类型的对象是对照片应用的所有的资源以及所有的集合进行管理的表现,包括了存储在本地设备上的资源和(如果允许的话)存储在iCloud上的资源。使用这个对象可以对照片库中的对象进行更改——例如,编辑资源数据或内容,插入一个新的资源,再或者更改一个集合中的成员。你也可以使用照片库对象注册Photos发送是否更改资源或集合的内容或者数据的消息,验证用户是否授权你的应用程序访问Photos的内容。
二、请求更改照片库
PHAsset,PHAssetCollection以及PHCollectionList
类型的实例是不可更改的对象。因此,想要修改Photos的资源或者集合,你应该使用共享的照片库来执行一个更改回调。在更改回调里面创建一个更改请求对象。你使用下面的“申请更改照片库”中的一个方法来申请一个更改回调。你在回调中申请的更改将在Photos运行这个回调并且调用你的完成处理回调之后生效。
每个更改请求的类——PHAssetChangeRequest,PHAssetCollectionChangeRequest和PHCollectionListChangeRequest——都对应一个资源或集合类。使用这些类来执行喜爱安的操作:
-
创建项。每个更改请求的类都提供方法,这些方法是用来请求创建一个新的对应的资源或集合类的项。。例如,使用
+ (instancetype)creationRequestForAssetCollectionWithTitle:(NSString *)title;
方法创建一个集合。
在更改回调中为了引用一个最近创建的请求——例如,添加一个资源到一个集合中——使用PHObjectPlaceholder对象提供的更改请求。更改回调执行完成后,使用占位对象的localIdentifier
属性来获取创建的对象。 -
删除项。每个更改请求的类都提供请求删除一个或多个对应的资源或集合类的方法。例如,使用
+ (void)deleteCollectionLists:(id<NSFastEnumeration>)collectionLists;
方法来删除一个集合列表。 -
更改项。你通过创建一个更改请求来修改一个存在的,以PHAsset、PHAssetCollection或PHCollectionList类的实例作为表现形式的资源或集合。例如,
+ (instancetype)changeRequestForAsset:(PHAsset *)asset;
方法创建一个更改请求,你可以用这个请求来修改一个资源。
创建一个更改请求后,使用这个更改请求的属性和实例方法来更改对应的资源或集合的表现形式中的属性。例如,设置一个资源的favorite
属性需要设置通过这个资源创建的更改请求的favorite
属性。想要添加一个资源集合,则调用一个资源集合更改请求的- (void)addAssets:(id<NSFastEnumeration>)assets;
方法。
使用一个更改回调在一个简单的更新中结合多个对照片库的更改。代码1展示了使用一个更改回调通过一个图片创建一个资源并且将这个资源添加到一个相簿中的例子。
代码1:
- (void)addNewAssetWithImage:(UIImage *)image toAlbum:(PHAssetCollection *)album {
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
// 请求通过一个图片创建一个资源。
PHAssetChangeRequest *createAssetRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
// 请求编辑这个相簿。
PHAssetCollectionChangeRequest *albumChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:album];
// 得到一个新的资源的占位对象并添加它到相簿编辑请求中。
PHObjectPlaceholder *assetPlaceholder = [createAssetRequest placeholderForCreatedAsset];
[albumChangeRequest addAssets:@[ assetPlaceholder ]];
} completionHandler:^(BOOL success, NSError *error) {
NSLog(@"Finished adding asset. %@", (success ? @"Success" : error));
}];
}
注意
对于每次调用- (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;
方法,Photos都会展示一个提示告诉用户,请求用户允许编辑照片库内容。如果你的应用程序需要同时提交几个更改,请将它们合并到一个更改回调中。
例如,一次添加几个新的图片,则在代码1中使用+ (instancetype)creationRequestForAssetFromImage:(UIImage *)image;
方法来创建多个PHAssetChangeRequest类型的对象。想要编辑多个存在的照片,创建多个PHAssetChangeRequest
对象,并且对每个的contentEditingOutput
属性设置一个独立的PHContentEditingOutput对象。
三、监听改变
想要接收照片库的改变通知,使用- (void)registerChangeObserver:(id<PHPhotoLibraryChangeObserver>)observer;
方法来注册一个监听器。
当你使用一个获取方法(例如+ (PHFetchResult<PHAsset *> *)fetchAssetsWithOptions:(PHFetchOptions *)options;
)来获取资源或者集合,Photos会自动注册你获取到的内容为监听器的监听内容。你执行完获取后,Photos会在这些内容发生获取请求更改时发送消息给你注册的监听器——包括了发生添加、移除或者重新对获取结果排序等改变。
关于处理更改的更详细内容,查看PHPhotoLibraryChangeObserver协议。
四、内容
1.验证授权
+ (PHAuthorizationStatus)authorizationStatus;
返回你的应用程序对于访问照片库的授权信息。
访问照片库必须需要授权。当你的应用第一次使用PHAsset、PHCollection、PHAssetCollection或PHCollectionList的方法来获取照片库的内容,或者使用下面的“申请更改照片库”中的方法来请求更改照片库的内容时,Photos都会自动的异步的向用户请求授权。
你的应用程序的Info.plist
文件必须给NSPhotoLibraryUsageDescription 键提供一个值来告诉用户为什么你的用户要请求相册资源。iOS 10.0之后的系统中,如果你的应用的Info.plist
文件中没有这个键值,那么你的应用将会直接崩溃。
在用户授权后,系统会记录用户对你的应用的授权,之后不会再次探出授权,但是用户可以在任何时间在设置应用中更改授权。如果用户已经拒绝了你的应用程序访问,或者还没有响应授权提示,或者不能授予访问权限,则任何试图获取照片库内容的请求都会返回空的PHFetchResult对象,任何试图执行对照片库的更改都会失败。
PHAuthorizationStatus
typedef NS_ENUM(NSInteger, PHAuthorizationStatus) {
PHAuthorizationStatusNotDetermined = 0, // 用户还没有对这个应用对访问照片库的权限的请求作出选择。
PHAuthorizationStatusRestricted, // 这个应用还没有被授权可以访问照片数据。
// 用户不能改变这个应用的授权状态,可能是由于活动限制,例如家长控制模式。
PHAuthorizationStatusDenied, // 用户已经明确的拒绝这个应用程序访问照片数据。
PHAuthorizationStatusAuthorized // 用户已经授权这个应用程序可以访问照片数据。
} PHOTOS_AVAILABLE_IOS_TVOS(8_0, 10_0);
如果这个方法返回PHAuthorizationStatusNotDetermined
,则你可以使用+ (void)requestAuthorization:(void (^)(PHAuthorizationStatus status))handler;
方法提示用户授权对照片库的访问。
这里苹果爸爸提供了一个监听授权更改变化的方法,但是经过实际测试,更改照片的访问权限都会在系统层面直接干掉你的应用程序。所以,监听不监听变化其实没什么用。不过我还是放在这里:
提示
在获取内容前使用- (void)registerChangeObserver:(id<PHPhotoLibraryChangeObserver>)observer;
方法监听图片库的改变。用户授权你的应用访问图片库之后,Photos会给你之前获取空的获取结果发送消息更改信息,来通知你这些获取的图片库内容现在是可用的了。
+ (void)requestAuthorization:(void(^)(PHAuthorizationStatus status))handler;
如果需要的话请求用户授权来使得应用可以访问照片库
当你的应用第一次使用PHAsset、PHCollection、PHAssetCollection或PHCollectionList方法来获取照片库的内容,或者使用下面的“申请更改照片库”中的方法来请求更改照片库的内容时,Photos都会自动的异步的向用户请求授权。或者你也可以使用此方法在你需要的时刻请求用户授权。
这个方法总是立即执行的。如果在之前用户已经授权或拒绝授权你的应用访问照片库,它会调用这个handler
回调,否则它会展示一个请求用户授权的提示框,在用户响应这个提示框之后调用handler
回调。
注意
Photos会在任意的串行队列上调用你的handler
回调,如果你的handler
回调中有需要与UI进行交互的内容,请将此工作分配到主线程。
2.获取共享照片库对象
+ (PHPhotoLibrary *)sharedPhotoLibrary;
获取获取共享照片库对象,即获取PHPhotoLibrary的单例。
你可以在任意线程中获取。
3.申请更改照片库
- (void)performChanges:(dispatch_block_t)changeBlock completionHandler:(nullable void(^)(BOOL success, NSError *__nullable error))completionHandler;
异步运行changeBlock
回调,来请求执行对照片库的修改。
Photos会在任意的串行队列上调用你的changeBlock
回调和handler
回调,如果你的回调中有需要与UI进行交互的内容,请将此工作分配到主线程。
对于每次调用此方法,Photos都会展示一个提示告诉用户,请求用户允许编辑照片库内容。如果你的应用程序需要同时提交几个更改,请将它们合并到一个changeBlock
中。详细见上面。
- (BOOL)performChangesAndWait:(dispatch_block_t)changeBlock error:(NSError *__autoreleasing *)error;
同步运行changeBlock
回调,来请求执行对照片库的修改。
不要再主线程中执行此方法。由于执行此方法会向用户请求编辑照片库的权限,并且需要一定的时间进行修改,所以在主线程中执行此方法可能会导致无限期的阻塞主线程。如果您需要在后台队列上执行工作则使用此方法,否则请使用上面的- (void)performChanges:(dispatch_block_t)changeBlock completionHandler:(nullable void(^)(BOOL success, NSError *__nullable error))completionHandler;
方法。
注意
这里给使用Swift的同学提个醒,在Swift中,此方法的error
回调是无效的,如果没有授权或者处理失败则会抛出错误。
4.监听图片库的变化
- (void)registerChangeObserver:(id<PHPhotoLibraryChangeObserver>)observer;
注册一个监听器,当图片库中的一个对象发生改变的时候接收通知。
监听变化后使用PHPhotoLibraryChangeObserver
协议接收更改。
当你使用一个获取方法(例如+ (PHFetchResult<PHAsset *> *)fetchAssetsWithOptions:(PHFetchOptions *)options;
)来获取资源或者集合时等于你隐式的注册了监听内容,Photos会自动注册你获取到的内容为监听器的监听内容。你执行完获取后,Photos会在这些内容发生获取请求更改时发送消息给你注册的监听器——包括了发生添加、移除或者重新对获取结果排序等改变。
- (void)unregisterChangeObserver:(id<PHPhotoLibraryChangeObserver>)observer;
移除一个已经注册的监听器,使得这个监听器不再接收图片库中一个对象的改变通知。