iOS系统相册基本操作

作者: 跑调的安眠曲 | 来源:发表于2016-05-09 23:53 被阅读3807次

    一、前言####

    在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

    如有什么疑问或者文中有不当之处,请指出,谢谢。祝大家好梦!

    相关文章

      网友评论

      • Happy晓哥:楼主,没有在info.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&quot;>
        <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&quot;>
        <plist version="1.0">
        <string>App需要您的同意,才能访问相机</string>
        </plist>
      • 开局四带二:demo 下载真机运行报错,虚拟机运行,创建失败
        开局四带二:@跑调的安眠曲 我可以跑起来了 现在有个问题,就是系统相册可以保存什么格式类型的文件呢?(我手头有个项目 ,要吧录音文件,存到系统相册文件下,不知道有没有办法??)
        跑调的安眠曲::disappointed_relieved: 不是吧?什么错?
      • vision_colion:楼主,如果想要实现拍照存到自己建的相册是不是得先存本地
      • 风语随风:我用一个非png格式的文件改成png的保存到自定义相册实际上失败了,但是success那块输出成功,请问这个怎么解决?
      • 岁月丿静好:请问获取自定义相册视频功能怎么写?
        跑调的安眠曲:@岁月丿静好 看产品怎么设计咯
      • 3c6544ed9c85:请问可以不出现提示框直接删除吗?
        7827ca403a04:请问一下,在app的documents 下放一个录制的视频,然后用上面的代码导到本地相册中,app中的文件还在不在呢?意思就是这个文件导出后是占了一份存储空间还是两份?
        跑调的安眠曲:@OYHeaven 不行的
      • chinwy:请问提示框能不能修改?
        42e1b2b337c4:@跑调的安眠曲 打错了,是中文
        42e1b2b337c4:@跑调的安眠曲 能不能改弹出框上的语言,比如中午或者日文
        跑调的安眠曲:@chinwy 你想怎么改?
      • 沙瓦迪卡:楼主可以发下源码不
        沙瓦迪卡:@跑调的安眠曲 谢谢楼主
        跑调的安眠曲:@沙瓦迪卡 https://github.com/GitterYang/YQSystemPhotoOperation
        跑调的安眠曲:@沙瓦迪卡 还需要吗?

      本文标题:iOS系统相册基本操作

      本文链接:https://www.haomeiwen.com/subject/hewerttx.html