热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

iOS相册备份功能实现

公司产品做了备份相关功能,主要是检测未备份的图片,上传。以及检测已备份却不在相册的图片,恢复。功能实现起来也不是很难,比对的话我用的MD5,进行比对文件是否重复,是否

     公司产品做了备份相关功能,主要是检测未备份的图片,上传。以及检测已备份却不在相册的图片,恢复。

     功能实现起来也不是很难,比对的话我用的MD5 ,进行比对文件是否重复,是否已上传 ,或未上传。MD5反正算是个问题,解决的办法不是很好,我会改进,因为功能急,暂时没有好的办法,只能 这么来了。具体怎么回事,我和大家说道说道。

     获取系统相册的图片,在iOS8之前,一直使用的是,但是iOS8 之后,苹果给我们提供了新的好用的photos framework。由于写的时候,没有研究过这个框架。所以还是使用的。这是之一。

    那么其二,就是枚举便利整个资源库,找出组。方法如下。

    if (isAutoBackupOfVideo||isAutoBackupOfPhoto) {
        if (!self.assetsLibrarry) {
            self.assetsLibrarry=[[ALAssetsLibrary alloc]init];
        }
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSMutableArray *groups=[NSMutableArray array];
            [self.assetsLibrarry enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
                if (group) {
                    [groups addObject:group];
                }else{
                    for (ALAssetsGroup *singeGroup in groups) {
                        NSString *albumName=[singeGroup valueForProperty:ALAssetsGroupPropertyName];
                        NSMutableArray *photos=[NSMutableArray array];
                        NSMutableArray *videos=[NSMutableArray array];
                        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                            [singeGroup enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
                                if (result) {
                                    if (IsEquallString(ALAssetTypePhoto, [result valueForProperty:ALAssetPropertyType])) {
                                        if (isAutoBackupOfPhoto) {
                                            Photo *photo=[[Photo alloc]init];
                                            photo.url=[[[result defaultRepresentation] url] absoluteString];
                                            photo.album=albumName;
                                            photo.thumbnail=[UIImage imageWithCGImage:[result thumbnail]];
                                            photo.name=[[result defaultRepresentation] filename];
                                            photo.type=[photo.name pathExtension];
                                            photo.size=[NSString stringWithFormat:@"%lld",[[result defaultRepresentation] size]];
                                            [photos addObject:result];
                                        }
                                    }
                                    if (IsEquallString(ALAssetTypeVideo, [result valueForProperty:ALAssetPropertyType])) {
                                        if (isAutoBackupOfVideo) {
                                            Video *video=[[Video alloc]init];
                                            video.url=[[[result defaultRepresentation] url] absoluteString];
                                            video.album=albumName;
                                            video.name=[[result defaultRepresentation] filename];
                                            video.type=[video.name pathExtension];
                                            video.thumbnail=[UIImage imageWithCGImage:[result thumbnail]];
                                            video.size=[NSString stringWithFormat:@"%lld",[[result defaultRepresentation] size]];
                                            [videos addObject:result];
                                        }
                                    }
                                }else{
                                    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                                        if (photos.count) {
                                            [self uploadPhoto:photos];
                                        }
                                        if (videos.count) {
                                            [self uploadVideos:videos];
                                        }
                                    });
                                }
                            }];
                        });
                        
                    }
                    
                }
                
            } failureBlock:^(NSError *error) {
            }];
        });
        
    }

你可以看见,资源库给你的是asset 对象,对象中有照片,也有视频。所以我们做了判断。判断依据就是ALAssetType。这里面有一个坑,在枚举方法的参数上。

enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop){}
WithTypes:(这个参数传递你想拿到的照片组类型)

enum {
    ALAssetsGroupLibrary     NS_ENUM_DEPRECATED_IOS(4_0, 9_0) = (1 <<0),         // The Library group that includes all assets.
    ALAssetsGroupAlbum       NS_ENUM_DEPRECATED_IOS(4_0, 9_0) = (1 <<1),         // All the albums synced from iTunes or created on the device.
    ALAssetsGroupEvent       NS_ENUM_DEPRECATED_IOS(4_0, 9_0) = (1 <<2),         // All the events synced from iTunes.
    ALAssetsGroupFaces       NS_ENUM_DEPRECATED_IOS(4_0, 9_0) = (1 <<3),         // All the faces albums synced from iTunes.
    ALAssetsGroupSavedPhotos NS_ENUM_DEPRECATED_IOS(4_0, 9_0) = (1 <<4),         // The Saved Photos album.
#if __IPHONE_5_0 <= __IPHONE_OS_VERSION_MAX_ALLOWED
    ALAssetsGroupPhotoStream NS_ENUM_DEPRECATED_IOS(5_0, 9_0) = (1 <<5),         // The PhotoStream album.
#endif
    ALAssetsGroupAll         NS_ENUM_DEPRECATED_IOS(4_0, 9_0) = 0xFFFFFFFF,       // The same as ORing together all the available group types,
};

看见这个,理所应当想到的是
ALAssetsGroupAll 
实际则不是,为什么呢,主要是照片流。照片流这个组的对象很奇怪,data是空得。我想想也是。照片流本身就是一个映射类似的存在。

还有就是。既然是对象,我们怎么算MD5值呢?

本以为直接读取二进制,data,算出MD5。但是结果算出来的值居然和文件本身的值不一样。没有深究为什么不一样,直接换了一种解决办法。直接把对象的image写入文件,计算文件的MD5,呵呵,对了。奇怪。

但是计算MD5其实不是一个很好的办法。为什么呢。因为速度慢啊。。。解决办法。想了一下。准备采取多值对比。(如:时间,名称),这样速度就会大幅度提升。


/*****************************************************分割线***********************************************/

下面讲讲另外一个值得注意的地方。那就是生命周期的问题。一个ALAssetsLibrary只在它自身的生命周期内有效。超出生命周期,那就导致你取不出来图片。简单来说,在一个ALAssetsLibrary的生命没有结束的时候,不要重新创建一个ALAssetsLibrary,这会结束上一个ALAssetsLibrary,导致文件提取不出来。

下面是,读取相册图片的MD5,及写入相册的源码。有需要的参考。

//获得本地图片的MD5数组
-(void)getLocalPhotos:(getLocalPhotosSuccessBlock)block{
    if (!self.assetsLibrarry) {
        self.assetsLibrarry=[[ALAssetsLibrary alloc]init];
    }
    
    NSMutableArray *groups=[NSMutableArray array];
    [self.assetsLibrarry enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
        if (group) {
            [groups addObject:group];
        }else{
            //
            
            for (ALAssetsGroup *singeGroup in groups) {
                NSString *albumName=[singeGroup valueForProperty:ALAssetsGroupPropertyName];
                NSMutableArray *photos=[NSMutableArray array];//存储ALAsset对象
                NSMutableArray * photoArr = [NSMutableArray array];//存储photo对象
                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                    [singeGroup enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
                        if (result) {
                            if (IsEquallString(ALAssetTypePhoto, [result valueForProperty:ALAssetPropertyType])) {
                                
                                Photo *photo=[[Photo alloc]init];
                                photo.url=[[[result defaultRepresentation] url] absoluteString];
                                photo.album=albumName;
                                photo.thumbnail=[UIImage imageWithCGImage:[result thumbnail]];
                                photo.name=[[result defaultRepresentation] filename];
                                photo.type=[photo.name pathExtension];
                                photo.md5 =[self getImageMD5WithUrl:result];
                                NSDate  * date = [result valueForProperty:ALAssetPropertyDate];
                                NSDateFormatter  *dateformatter=[[NSDateFormatter alloc] init];
                                dateformatter.dateFormat=@"YYYY-MM-dd HH:mm:ss";
                                photo.lastWriteTime = [dateformatter stringFromDate:date];
                                photo.size=[NSString stringWithFormat:@"%lld",[[result defaultRepresentation] size]];
                                photo.result = result;
                                [photos addObject:result];
                                [photoArr addObject:photo];
                                
                            }
                        }else{
                            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                                if (photoArr.count) {
                                    block(photoArr);
                                }
                            });
                        }
                    }];
                });
            }
            //
        }
        
    } failureBlock:^(NSError *error) {
    }];
}

//写入相册
-(void)storeFinishByTypeFile:(TypeFile*)typeFile andIsSuccess:(BOOL)isSuccess{
    if (isSuccess) {
        NSString *path=[self getFilePathWithFile:typeFile];
        NSData *imageData=[NSData dataWithContentsOfFile:path];
        UIImage *image=[UIImage imageWithData:imageData];
        if (!self.assetsLibrarry) {
            self.assetsLibrarry = [[ALAssetsLibrary alloc]init];
        }
        [self.assetsLibrarry writeImageToSavedPhotosAlbum:image.CGImage orientation:(ALAssetOrientation)image.imageOrientation completionBlock:^(NSURL* assetURL, NSError* error) {
            if (error!=nil) {
                [Utils showAlertViewByText:[NSString stringWithFormat:@"%@保存失败",typeFile.name]];
            }else{
                typeFile.url=[assetURL description];
                NSLog(@"Success--%@",typeFile.url);
                [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
                
            }
        }];
    }else{
        [Utils showAlertViewByText:[NSString stringWithFormat:@"%@保存失败",typeFile.name]];
    }
}

在备份上传前做判断:
for (ALAsset *asset in photos) {
                    NSString * MD5Str = [self getImageMD5WithUrl:asset ];
                    if (MD5Str.length>0) {
                        [[RequestIP shardRequestIP].localMd5Arr addObject:MD5Str];
                        if([MD5Arr indexOfObject:MD5Str]== NSNotFound){
                            NSLog(@"NSNotFound!");
                            if ([uploadArr indexOfObject:MD5Str] == NSNotFound) {
                                [uploadArr addObject:MD5Str];
                                NSLog(@"MD5Str:%@",MD5Str);
                                if (!IS_AUTO_CopyPhotos) {
                                    break;
                                }

大概 也就这么多。详细的源码,我就不发出来了。有不懂得可以咨询我。



推荐阅读
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文讨论了编写可保护的代码的重要性,包括提高代码的可读性、可调试性和直观性。同时介绍了优化代码的方法,如代码格式化、解释函数和提炼函数等。还提到了一些常见的坏代码味道,如不规范的命名、重复代码、过长的函数和参数列表等。最后,介绍了如何处理数据泥团和进行函数重构,以提高代码质量和可维护性。 ... [详细]
  • AFNetwork框架(零)使用NSURLSession进行网络请求
    本文介绍了AFNetwork框架中使用NSURLSession进行网络请求的方法,包括NSURLSession的配置、请求的创建和执行等步骤。同时还介绍了NSURLSessionDelegate和NSURLSessionConfiguration的相关内容。通过本文可以了解到AFNetwork框架中使用NSURLSession进行网络请求的基本流程和注意事项。 ... [详细]
  • Java大文件HTTP断点续传到服务器该怎么做?
    最近由于笔者所在的研发集团产品需要,需要支持高性能的大文件http上传,并且要求支持http断点续传。这里在简要归纳一下,方便记忆 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • Python爬虫中使用正则表达式的方法和注意事项
    本文介绍了在Python爬虫中使用正则表达式的方法和注意事项。首先解释了爬虫的四个主要步骤,并强调了正则表达式在数据处理中的重要性。然后详细介绍了正则表达式的概念和用法,包括检索、替换和过滤文本的功能。同时提到了re模块是Python内置的用于处理正则表达式的模块,并给出了使用正则表达式时需要注意的特殊字符转义和原始字符串的用法。通过本文的学习,读者可以掌握在Python爬虫中使用正则表达式的技巧和方法。 ... [详细]
  • 本文介绍了使用FormData对象上传文件同时附带其他参数的方法。通过创建一个表单,将文件和参数添加到FormData对象中,然后使用ajax发送POST请求进行文件上传。在发送请求时,需要设置processData为false,告诉jquery不要处理发送的数据;同时设置contentType为false,告诉jquery不要设置content-Type请求头。 ... [详细]
  • 在tp5项目中引入ueditor编辑器并实例化后插入图片出现目录创建失败问题在查看网络上各种解决方案之后总结如下:根据官网提示主要是因为图片保存的路径无权限导致,官方文档链接:ht ... [详细]
  • 基于分布式锁的防止重复请求解决方案
    一、前言关于重复请求,指的是我们服务端接收到很短的时间内的多个相同内容的重复请求。而这样的重复请求如果是幂等的(每次请求的结果都相同,如查 ... [详细]
author-avatar
减肥瘦身666
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有