一、前言####
在iOS8以前,我们操作系统相册,一般使用<AssetsLibrary/AssetsLibrary.h>
库进行操作,iOS8以后,Apple推出了<Photos/Photos.h>
库,以提升操作系统相册的效率。针对目前iOS8及以上用户占有率已超过95%,本文将采用<Photos/Photos.h>
库进行开发说明。
二、针对系统相册的操作####
思路:为了满足保存视频/图片到系统相册指定路径,并随时准备删除的变态需求,首先得弄清
<Photos/Photos.h>
库,保存一般都好说,但是想删除系统相册中的某个图片或者视频,第一印象就根据保存的文件名来进行删除,可是使用过该api之后,发现存在系统相册之后的名字根本就不是你原来存的那个名字,fileName也没有对外提供给你使用,但是它提供了localIdentifier
字段,用来唯一标识系统相册中的元素,那么事情就好办了,我们在进行保存图片或者视频的时候,将其localIdentifier
缓存到一个plist
文件中,然后每次删除的时候,通过对应的文件名找到相应的localIdentifier
就可以进行删除了。
- 判断系统相册中是否存在该指定的文件夹
- (BOOL)isExistFolder:(NSString *)folderName {
//首先获取用户手动创建相册的集合
PHFetchResult *collectonResuts = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];
__block BOOL isExisted = NO;
//对获取到集合进行遍历
[collectonResuts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
PHAssetCollection *assetCollection = obj;
//folderName是我们写入照片的相册
if ([assetCollection.localizedTitle isEqualToString:folderName]) {
isExisted = YES;
}
}];
return isExisted;
}
- 在系统相册中创建指定的文件夹
- (void)createFolder:(NSString *)folderName {
if (![self isExistFolder:folderName]) {
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
//添加HUD文件夹
[PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:folderName];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
if (success) {
NSLog(@"创建相册文件夹成功!");
} else {
NSLog(@"创建相册文件夹失败:%@", error);
}
}];
}
}
- 保存图片到系统相册指定目录
- (void)saveImagePath:(NSString *)imagePath{
NSURL *url = [NSURL fileURLWithPath:imagePath];
//标识保存到系统相册中的标识
__block NSString *localIdentifier;
//首先获取相册的集合
PHFetchResult *collectonResuts = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];
//对获取到集合进行遍历
[collectonResuts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
PHAssetCollection *assetCollection = obj;
//Camera Roll是我们写入照片的相册
if ([assetCollection.localizedTitle isEqualToString:_folderName]) {
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
//请求创建一个Asset
PHAssetChangeRequest *assetRequest = [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:url];
//请求编辑相册
PHAssetCollectionChangeRequest *collectonRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
//为Asset创建一个占位符,放到相册编辑请求中
PHObjectPlaceholder *placeHolder = [assetRequest placeholderForCreatedAsset];
//相册中添加照片
[collectonRequest addAssets:@[placeHolder]];
localIdentifier = placeHolder.localIdentifier;
} completionHandler:^(BOOL success, NSError *error) {
if (success) {
NSLog(@"保存图片成功!");
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[self readFromPlist]];
[dict setObject:localIdentifier forKey:[self showFileNameFromPath:imagePath]];
[self writeDicToPlist:dict];
} else {
NSLog(@"保存图片失败:%@", error);
}
}];
}
}];
}
- 保存视频到系统相册指定目录
- (void)saveVideoPath:(NSString *)videoPath {
NSURL *url = [NSURL fileURLWithPath:videoPath];
//标识保存到系统相册中的标识
__block NSString *localIdentifier;
//首先获取相册的集合
PHFetchResult *collectonResuts = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];
//对获取到集合进行遍历
[collectonResuts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
PHAssetCollection *assetCollection = obj;
//folderName是我们写入照片的相册
if ([assetCollection.localizedTitle isEqualToString:_folderName]) {
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
//请求创建一个Asset
PHAssetChangeRequest *assetRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:url];
//请求编辑相册
PHAssetCollectionChangeRequest *collectonRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
//为Asset创建一个占位符,放到相册编辑请求中
PHObjectPlaceholder *placeHolder = [assetRequest placeholderForCreatedAsset];
//相册中添加视频
[collectonRequest addAssets:@[placeHolder]];
localIdentifier = placeHolder.localIdentifier;
} completionHandler:^(BOOL success, NSError *error) {
if (success) {
NSLog(@"保存视频成功!");
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[self readFromPlist]];
[dict setObject:localIdentifier forKey:[self showFileNameFromPath:videoPath]];
[self writeDicToPlist:dict];
} else {
NSLog(@"保存视频失败:%@", error);
}
}];
}
}];
}
- 删除系统相册指定目录下的文件
- (void)deleteFile:(NSString *)filePath {
if ([self isExistFolder:_folderName]) {
//获取需要删除文件的localIdentifier
NSDictionary *dict = [self readFromPlist];
NSString *localIdentifier = [dict valueForKey:[self showFileNameFromPath:filePath]];
PHFetchResult *collectonResuts = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];
[collectonResuts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
PHAssetCollection *assetCollection = obj;
if ([assetCollection.localizedTitle isEqualToString:_folderName]) {
PHFetchResult *assetResult = [PHAsset fetchAssetsInAssetCollection:assetCollection options:[PHFetchOptions new]];
[assetResult enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
PHAsset *asset = obj;
if ([localIdentifier isEqualToString:asset.localIdentifier]) {
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetChangeRequest deleteAssets:@[obj]];
} completionHandler:^(BOOL success, NSError *error) {
if (success) {
NSLog(@"删除成功!");
NSMutableDictionary *updateDic = [NSMutableDictionary dictionaryWithDictionary:dict];
[updateDic removeObjectForKey:[self showFileNameFromPath:filePath]];
[self writeDicToPlist:updateDic];
} else {
NSLog(@"删除失败:%@", error);
}
}];
}
}];
}
}];
}
}
下面给出具体的实现代码:######
头文件定义如下:
#import <Foundation/Foundation.h>
@interface YQAssetOperator : NSObject
/**
* 初始化方法
*
* @param folderName 操作的目录文件
*
* @return 操作对象
*/
- (instancetype)initWithFolderName:(NSString *)folderName;
/**
* 保存图片到系统相册
*
* @param imagePath 保存的图片路径
* @param folderName 目的文件的路径
*/
- (void)saveImagePath:(NSString *)imagePath;
/**
* 保存视频到系统相册
*
* @param videoPath 保存的视频路径
* @param folderName 目的文件的路径
*/
- (void)saveVideoPath:(NSString *)videoPath;
/**
* 删除系统相册中的文件
*
* @param filePath 文件的路径
* @param folderName 文件夹的名字
*/
- (void)deleteFile:(NSString *)filePath;
@end
实现文件:
#import "YQAssetOperator.h"
#import <Photos/Photos.h>
@interface YQAssetOperator ()
@property (nonatomic, copy) NSString *plistName;
@property (nonatomic, copy) NSString *folderName;
@end
@implementation YQAssetOperator
- (instancetype)initWithFolderName:(NSString *)folderName {
self = [self init];
if (self) {
self.plistName = @"Asset";
self.folderName = folderName;
}
return self;
}
- (void)saveImagePath:(NSString *)imagePath{
NSURL *url = [NSURL fileURLWithPath:imagePath];
//标识保存到系统相册中的标识
__block NSString *localIdentifier;
//首先获取相册的集合
PHFetchResult *collectonResuts = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];
//对获取到集合进行遍历
[collectonResuts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
PHAssetCollection *assetCollection = obj;
//Camera Roll是我们写入照片的相册
if ([assetCollection.localizedTitle isEqualToString:_folderName]) {
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
//请求创建一个Asset
PHAssetChangeRequest *assetRequest = [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:url];
//请求编辑相册
PHAssetCollectionChangeRequest *collectonRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
//为Asset创建一个占位符,放到相册编辑请求中
PHObjectPlaceholder *placeHolder = [assetRequest placeholderForCreatedAsset];
//相册中添加照片
[collectonRequest addAssets:@[placeHolder]];
localIdentifier = placeHolder.localIdentifier;
} completionHandler:^(BOOL success, NSError *error) {
if (success) {
NSLog(@"保存图片成功!");
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[self readFromPlist]];
[dict setObject:localIdentifier forKey:[self showFileNameFromPath:imagePath]];
[self writeDicToPlist:dict];
} else {
NSLog(@"保存图片失败:%@", error);
}
}];
}
}];
}
- (void)saveVideoPath:(NSString *)videoPath {
NSURL *url = [NSURL fileURLWithPath:videoPath];
//标识保存到系统相册中的标识
__block NSString *localIdentifier;
//首先获取相册的集合
PHFetchResult *collectonResuts = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];
//对获取到集合进行遍历
[collectonResuts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
PHAssetCollection *assetCollection = obj;
//folderName是我们写入照片的相册
if ([assetCollection.localizedTitle isEqualToString:_folderName]) {
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
//请求创建一个Asset
PHAssetChangeRequest *assetRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:url];
//请求编辑相册
PHAssetCollectionChangeRequest *collectonRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
//为Asset创建一个占位符,放到相册编辑请求中
PHObjectPlaceholder *placeHolder = [assetRequest placeholderForCreatedAsset];
//相册中添加视频
[collectonRequest addAssets:@[placeHolder]];
localIdentifier = placeHolder.localIdentifier;
} completionHandler:^(BOOL success, NSError *error) {
if (success) {
NSLog(@"保存视频成功!");
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[self readFromPlist]];
[dict setObject:localIdentifier forKey:[self showFileNameFromPath:videoPath]];
[self writeDicToPlist:dict];
} else {
NSLog(@"保存视频失败:%@", error);
}
}];
}
}];
}
- (void)deleteFile:(NSString *)filePath {
if ([self isExistFolder:_folderName]) {
//获取需要删除文件的localIdentifier
NSDictionary *dict = [self readFromPlist];
NSString *localIdentifier = [dict valueForKey:[self showFileNameFromPath:filePath]];
PHFetchResult *collectonResuts = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];
[collectonResuts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
PHAssetCollection *assetCollection = obj;
if ([assetCollection.localizedTitle isEqualToString:_folderName]) {
PHFetchResult *assetResult = [PHAsset fetchAssetsInAssetCollection:assetCollection options:[PHFetchOptions new]];
[assetResult enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
PHAsset *asset = obj;
if ([localIdentifier isEqualToString:asset.localIdentifier]) {
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetChangeRequest deleteAssets:@[obj]];
} completionHandler:^(BOOL success, NSError *error) {
if (success) {
NSLog(@"删除成功!");
NSMutableDictionary *updateDic = [NSMutableDictionary dictionaryWithDictionary:dict];
[updateDic removeObjectForKey:[self showFileNameFromPath:filePath]];
[self writeDicToPlist:updateDic];
} else {
NSLog(@"删除失败:%@", error);
}
}];
}
}];
}
}];
}
}
- (BOOL)isExistFolder:(NSString *)folderName {
//首先获取用户手动创建相册的集合
PHFetchResult *collectonResuts = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];
__block BOOL isExisted = NO;
//对获取到集合进行遍历
[collectonResuts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
PHAssetCollection *assetCollection = obj;
//folderName是我们写入照片的相册
if ([assetCollection.localizedTitle isEqualToString:folderName]) {
isExisted = YES;
}
}];
return isExisted;
}
- (void)createFolder:(NSString *)folderName {
if (![self isExistFolder:folderName]) {
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
//添加HUD文件夹
[PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:folderName];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
if (success) {
NSLog(@"创建相册文件夹成功!");
} else {
NSLog(@"创建相册文件夹失败:%@", error);
}
}];
}
}
#pragma mark - setters和getters
- (void)setFolderName:(NSString *)folderName {
if (!_folderName) {
_folderName = folderName;
[self createFolder:folderName];
}
}
- (void)setPlistName:(NSString *)plistName {
if (!_plistName) {
_plistName = plistName;
//创建plist文件,记录path和localIdentifier的对应关系
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *path = [paths objectAtIndex:0];
NSString *filePath = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.plist", plistName]];
NSLog(@"plist路径:%@", filePath);
NSFileManager* fm = [NSFileManager defaultManager];
if (![fm fileExistsAtPath:filePath]) {
BOOL success = [fm createFileAtPath:filePath contents:nil attributes:nil];
if (!success) {
NSLog(@"创建plist文件失败!");
} else {
NSLog(@"创建plist文件成功!");
}
} else {
NSLog(@"沙盒中已有该plist文件,无需创建!");
}
}
}
#pragma mark - 写入plist文件
- (void)writeDicToPlist:(NSDictionary *)dict {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *path = [paths objectAtIndex:0];
NSString *filePath = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.plist", _plistName]];
[dict writeToFile:filePath atomically:YES];
}
#pragma mark - 读取plist文件
- (NSDictionary *)readFromPlist {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *path = [paths objectAtIndex:0];
NSString *filePath = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.plist", _plistName]];
return [NSDictionary dictionaryWithContentsOfFile:filePath];
}
#pragma mark - 根据路径获取文件名
- (NSString *)showFileNameFromPath:(NSString *)path {
return [NSString stringWithFormat:@"%@", [[path componentsSeparatedByString:@"/"] lastObject]];
}
@end
测试程序:
#import "ViewController.h"
#import "YQAssetOperator.h"
@interface ViewController (){
YQAssetOperator *_assetOperator;
}
- (IBAction)deleteFile:(UIButton *)sender;
- (IBAction)addFiles:(UIButton *)sender;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor grayColor];
_assetOperator = [[YQAssetOperator alloc] initWithFolderName:@"LOVE"];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)deleteFile:(UIButton *)sender {
NSString *videoPath =[[NSBundle mainBundle] pathForResource:@"0425_103546" ofType:@"mp4"];
[_assetOperator deleteFile:videoPath];
}
- (IBAction)addFiles:(UIButton *)sender {
//保存图片
NSString *imagePath =[[NSBundle mainBundle] pathForResource:@"scanner" ofType:@"png"];
[_assetOperator saveImagePath:imagePath];
//保存视频
NSString *videoPath =[[NSBundle mainBundle] pathForResource:@"0425_103546" ofType:@"mp4"];
[_assetOperator saveVideoPath:videoPath];
}
@end
测试程序将一个二维码图片和一段视频存入了"LOVE"文件夹中,效果图如下:
效果图源码地址:https://github.com/GitterYang/YQSystemPhotoOperation
如有什么疑问或者文中有不当之处,请指出,谢谢。祝大家好梦!
网友评论
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<string>App需要您的同意,才能访问相册</string>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<string>App需要您的同意,才能访问相机</string>
</plist>