一、前言
因为一些原因,软件迄今发了三个版本,就进行了三次大的改版,因为每次都是从底层开始修改,虽然要了命了,但是作为开发来说也只能听天由命啦,大版本一直在抢分多秒的开发阶段,并没有做什么优化,当然现在说的优化也是基于当前的2.3.2版本的,至于后面会不会再次大改版重新优化,或者因为又是从底层修改导致删除掉这些优化,其实都是未知的,所以文章的标题就写成2.3.2版本优化吧。
二、优化内容
2.1、网络接收内容判断
网络库是使用的AFNetworking,所以接受数据已经处理好了,但是之前并没有考虑到网络数据的丢失,后面发现居然会出现响应是ok的,但是返回的数据却是空的,这样就导致在接受到数据之后直接用字典执行[dic setObject: forKey:]
的时候,因为对象时nil,直接导致崩溃的问题。
所以在这个版本,重新创建了一个类专门用来检测接受数据的类型和值的,如果指定的字段的类型和指定的值不一样的话,就会报错并且异步返回给服务器报错的接口、接收的数据、发送的数据和UA的内容,比如这样
if ([[responseObject objectForKey:@"ok"] integerValue] == 1) {
YZNetReciveParamCheckTools *checkDic = [[YZNetReciveParamCheckTools alloc] initWithDictionary:[responseObject objectForKey:@"data"] withPostErrorWithUrl:kYZUrl_Make_UploadVideoPhoto param:dic];
[checkDic addCheckParamName:@"user_resume_id" withType:kYZNetErrorParamNone canNil:NO];
if (![checkDic isAccord]) {
return;
}
}
判断的内容主要就是基于类型和值来判断,有的值允许为空,所以就增加了允许为空的选项,现在主要是这几个方法。如果有人需要,可以留言,我去整理分享一下。
@interface YZNetReciveParamCheckTools : NSObject
/**
初始化操作
@param dic 要检测的返回的dic
@param url 请求的URL
@param param 请求数据的参数
@return 初始化完成
*/
-(instancetype)initWithDictionary:(NSDictionary*)dic withPostErrorWithUrl:(NSString*)url param:(NSDictionary*)param;
/**
添加检测的字段
@param name 字段key值
@param paramType 字段指定的类型
@param canNil 是否可空
*/
-(void)addCheckParamName:(NSString*)name withType:(YZNetErrorParamType)paramType canNil:(BOOL)canNil;
/**
批量添加检测的字段,全部为空,或者全部不能为空
@param nameArray 字段key值的数组
@param paramTypeArray 类型数组
@param canNil 是否全部可空
*/
-(void)addCheckParamNameArray:(NSArray*)nameArray withTypeArray:(NSArray*)paramTypeArray canNilTotal:(BOOL)canNil;
/**
批量添加检测的字段
@param nameArray 字段key值的数组
@param paramTypeArray 类型数组
@param canNilArray 是否可空数组
*/
-(void)addCheckParamNameArray:(NSArray*)nameArray withTypeArray:(NSArray*)paramTypeArray canNilArray:(NSArray*)canNilArray;
/**
检测是否符合要求
@return 是否符合要求
*/
-(BOOL)isAccord;
@end
这样在使用之前就会先增加一份网络数据的保障。
2.2、字典的对象空处理
正如前面说的,网络的空数据会导致字典崩溃,那其他的设置为空也是一样的,所以对字典设值的时候也可以验证下,github上面有一个NSDictionry+nil的库,是动态设置的,但是这个库会在全局都生效,会导致在使用AVFoundation合成视频的时候合成失败。
所以根据暂时常使用的字符串、字典、数组来通过类型和值去安全设置,如果是空的就自己初始化,保证不为nil即可
#import <Foundation/Foundation.h>
@interface NSMutableDictionary (SafeValue)
///暂时用于字符串、字典、数组
-(void)setSafeObject:(id)object withClass:(Class)cls forKey:(NSString *)key;
///暂时用于字符串、字典、数组
-(id)objectSafeForKey:(NSString*)key withClass:(Class)cls;
@end
而判空也是根据工程的具体情况去判断空,判断的不仅仅只是nil,还判断了值是否为0,是否因为强转造成的"null","
///判断是否为空
-(BOOL)IsNotNull
{
if (!self && ![self isEqual:[NSNull null]]) {
return YES;
}
else{
if ([self isKindOfClass:[NSString class]]) {
if ([((NSString*)self) isEqualToString:@"null"] || [((NSString*)self) isEqualToString:@"<null>"] || [((NSString*)self) isEqualToString:@"(null)"]) {
return NO;
}
return ((NSString*)self).length>0;
}
if ([self isKindOfClass:[NSArray class]]) {
return [((NSArray*)self) count]>0;
}
if ([self isKindOfClass:[NSSet class]]) {
return [(NSSet*)self count]>0;
}
if ([self isKindOfClass:[NSDictionary class]]) {
return [((NSDictionary*)self) allKeys].count>0;
}
if ([self isKindOfClass:[NSNumber class]]) {
return [(NSNumber*)self integerValue] > 0;
}
if ([self isKindOfClass:[UIImage class]]) {
NSData *data1 = UIImagePNGRepresentation((UIImage*)self);
return data1.length>0;
}
// else{
// DebugLog(@"无法判断该类型:%@",self);
// NSAssert(NO, @"无法判断该类型");
// }
return NO;
}
}
经过这些处理,在对象为空或者服务器返回错误造成的崩溃会减少很多。
2.3、文件和文件夹的分类管理
之前版本不太考虑多用户共存问题,主要考虑的就是用户切换使用等,但是这个版本我们考虑为了用户更加快捷,便利,所以对每个用户ID的文件夹、文件都分类处理,这个思路主要参考了腾讯QQ的多用户登陆、文件的管理方式。
#import <Foundation/Foundation.h>
#import "YZConfig.h"
///管理软件内的文件创建、删除
@interface YZFileManageTools : NSObject
///单例
+(instancetype)shareYZFileManageTools;
///初始化所需要的所有文件夹
-(void)initSystermFolder;
///在指定文件夹中增加文件
-(BOOL)addFileToFolder:(YZFolderType)folderType withFileName:(NSString*)fileName withFilePath:(NSString*)filePath withCopyModel:(YZCopyModel)copyModel;
///删除指定的文件夹的指定文件内容
-(BOOL)deleteFileFromFolder:(YZFolderType)folderType withFileName:(NSString*)fileName;
///删除指定文件夹里的所有内容
-(BOOL)deleteFilesInFolder:(YZFolderType)folderType;
///获取指定文件夹的路径
-(NSString*)getFilePathFromFolder:(YZFolderType)folderType;
///获取指定文件夹中的所有文件路径
-(NSArray*)getAllFilePathInFolder:(YZFolderType)folderType;
///获取指定文件夹的指定文件的路径
-(NSString*)getFilePathFromFolder:(YZFolderType)folderType withFileName:(NSString*)fileName;
///删除sdkwebimage和网页缓存
-(BOOL)cleanPlusMemory;
///删除账户自己的缓存文件,会删除数据库,导致做的简历缓存丢失
-(BOOL)cleanSelfFileMemory;
///深度清理app内所有的缓存,会删除数据库,导致做的简历缓存丢失
-(BOOL)deepCleanAllFileMemory;
@end
这里在初始化的时候,我们会根据用户ID去创建对应的文件夹类型和文件夹
///初始化所需要的所有文件夹
-(void)initSystermFolder
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
////////用户的总目录
_userFolder = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"userFolder%@",[[YZUserInfoData sharedYZUserInfoData] getUserUIDStr]]];
DebugLog(@"用户的目录:%@",_userFolder);
///用户的录制视频的目录
NSString *recodeFolder = [_userFolder stringByAppendingPathComponent:kYZVideoFolder];
NSString *tempVideoFolder = [_userFolder stringByAppendingPathComponent:kYZTempVideoFolder];
NSString *musicVideoFolder = [_userFolder stringByAppendingPathComponent:kYZTempMusicVideoFolder];
NSString *waterVideoFolder = [_userFolder stringByAppendingPathComponent:kYZWaterVideoFolder];
///用户的封面图文件夹
NSString *coverImageFolder = [_userFolder stringByAppendingPathComponent:kYZCoverimgFolder];
///用户的照片文件夹
NSString *photoFolder = [_userFolder stringByAppendingPathComponent:kYZPhotoFolder];
///用户的数据库文件夹
NSString *dataBaseFolder = [_userFolder stringByAppendingPathComponent:kYZDataBaseFolder];
////////公共目录
_commonFolder = [path stringByAppendingPathComponent:@"commonFolder"];
DebugLog(@"公共目录:%@",_commonFolder);
///音乐目录
NSString *music = [_commonFolder stringByAppendingPathComponent:kYZMusicFolder];
///创建的目录
NSArray *folerArray = [NSArray arrayWithObjects:_userFolder,recodeFolder,tempVideoFolder,musicVideoFolder,waterVideoFolder,coverImageFolder,photoFolder,dataBaseFolder,_commonFolder,music, nil];
NSFileManager *fileManager = [NSFileManager defaultManager];
for (int i = 0; i<folerArray.count; i++) {
BOOL isDir = FALSE;
BOOL isDirExist = [fileManager fileExistsAtPath:[folerArray objectAtIndex:i] isDirectory:&isDir];
if(!(isDirExist && isDir))
{
BOOL bCreateDir = [fileManager createDirectoryAtPath:[folerArray objectAtIndex:i] withIntermediateDirectories:YES attributes:nil error:nil];
if(!bCreateDir){
DebugLog(@"创建文件夹失败");
}
}
}
}
通过这些措施,对于每个用户的文件夹和文件路径都能轻易获取管理,清理缓存等等都会很有序进行,而对多用户的存在也不会产生影响,避免数据冲突串用。
2.4、数据库缓存和记录
之前存储更多的是使用NSUserDefault,这次为了更好的管理数据和更快的处理和后期的处理,所以采取用数据库存储部分数据和缓存。经过对比,采用了比iOS自带的sqlite更效率的微信的开源数据库WCDB,这个数据库性能比FMDB更加强悍,所以就采用了这个。
管理数据库主要就是判断是否存在,存在就读取数据,不存在去创建或者更新数据
#import <Foundation/Foundation.h>
@interface YZDataBaseTools : NSObject
+(instancetype)sharedYZDataBaseTools;
///是否存在该userID的数据库,以及在指定表中的类是否存在
-(BOOL)isExitTheDataBase:(Class)cls fromTable:(NSString*)tableName;
///获取数据库路径地址
-(NSString*)getDataBasePath;
///清理数据库
-(BOOL)cleanDataBase;
@end
三、后续优化计划
不知道后续版本是否会大改,如果大改的话就省掉这段吧,如果没有的话,后续的优化计划主要就是针对网速差的优化。
3.1、首先网络优化
网络有时候还是不太尽如人意,虽然采取了多种措施,但是谁能保证用户的网络质量呢,有的用户手机上虽然显示的是4G,但是网速却是2G吧,所以还是要优化网络质量差的情况。
3.2、低网速界面操作优化
界面是反馈一个软件质量的最直观反应,之前并没有考虑太多网速的因素,因为并没有考虑太多用户会在地铁上、偏远展厅等地方使用的场景。所以网速垃圾的情况下,会出现一系列问题,虽然这个版本已经进行了不少优化,但是因为相比上个版本,修改的东西太多,所以还是需要分阶段来进行。
3.3、对内存、缓存的控制
下一步会尽量充分使用内存和缓存的使用,尽量在低网速操作也能享受到畅快的舒爽
四、结语
优化是动态的,现在这个版本的优化对版本稳定性起了很大的帮助,当然也会根据项目的变动变动,对该项目比较大的优化就是这几个,当然为了增强用户体验也做了一些小的优化,那些就暂时不提了。该软件版本马上就要上线,欢迎大家使用哦。
版权属于:东哥笔记 - DongGe.me
本文链接:https://dongge.org/blog/581.html
自2017年12月26日起,『转载以及大段采集进行后续编辑』须注明本文标题和链接!否则禁止所有转载和采集行为!
1 条评论
不错