这里简单的封装一下iOSAPP数据本地存储工具类,为什么要封装?
1.使用起来方便,就算是用NSUserDefaults存储一个数据也需要好几句代码,封装后一句代码存取。可以跨类全局存取。
如我这里要存取用户信息(是不是使用很简单):
//存自定义对象
JYUserModel * dataModel = [[JYUserModel alloc]init];
dataModel.userNickname = @"nickname";
dataModel.userId = @"id";
[[JYData shareData] saveUserData:dataModel];
//取自定义对象
JYUserModel * dataModel = [[JYData shareData]getUserData];
//存数字
[[JYData shareData]saveInt:27 forKey:@"UserAge"]
//取数字
int age = [[JYData shareData]getIntForKey:@"UserAge"];
2.能够很好的解耦存储方式与工程代码,比如用序列化方式改为数据库存储方式,工程中代码不需要改变,只要修改存储工具类即可。
3.管理方便,如可以存储到document目录下面可以用itunes查看,并且不惧大文件几十M上百M都可以。还可很方便的根据不同用户分开保存数据,根据需求清理数据。
这里用序列化方式存储数据到本地document目录下面。如下图(iTunes里面查看,UserDataFiles目录就是):
如下,根据不同用户分目录存储数据(这里根据不同手机号区分):
下面上代码,这里包括自定义对象,OC对象,基本数据类型存储(可直接拷贝使用的哦):
JYData.h
//
// JYData.h
// F2
//
// Created by zhangdan on 2018/4/12.
// Copyright © 2018年 szjy. All rights reserved.
//
#import <Foundation/Foundation.h>
//自定义对象
#import "FUAvatar.h"
#import "JYUserModel.h"
#import "JYSubjectsModel.h"
/**
Description
注意 想要保存自定义对象需要把下面宏添加到自定义类中
*/
//MJCodingImplementation
@interface JYData : NSObject
+ (instancetype)shareData;
/**
Description
@param phoneNum 手机号
@return 以此来识别不同用户数据
*/
- (BOOL)createDataID:(NSInteger)phoneNum;
- (NSInteger)getDataID;
/**
数组或者字典都可以存储,但是里面的数据必须为oc对象数据类型
如果数组里是自定义类型参照最后说明
自己添加存储方法
*/
- (BOOL)saveObject:(id)value forKey:(NSString*)key;
- (id)getObjectForKey:(NSString*)key;
- (void)setURL:(NSURL*)URL forKey:(NSString*)key;
- (NSURL*)getUrlForkey:(NSString*)key;
- (void)saveInteger:(NSInteger)integer forKey:(NSString*)key;
- (NSInteger)getIntegerForKey:(NSString*)key;
- (void)saveInt:(int)value forKey:(NSString*)key;
- (int)getIntForKey:(NSString*)key;
- (void)saveFloat:(float)value forKey:(NSString*)key;
- (float)getFloat:(NSString*)key;
- (void)saveDouble:(double)value forKey:(NSString*)key;
- (double)getDouble:(NSString*)key;
- (void)saveBool:(BOOL)value forKey:(NSString*)key;
- (BOOL)getBool:(NSString*)key;
//自定义对象及对象数组存取
- (BOOL)saveAvatar:(FUAvatar*)avatar forKey:(NSString*)key;
- (FUAvatar*)getAvatarForKey:(NSString*)key;
- (BOOL)saveAvatarArr:(NSArray*)arr forKey:(NSString*)key;
- (NSArray*)getAvatarArrForKey:(NSString*)key;
//自定义对象及对象数组存取
- (BOOL)saveSubjectArr:(NSArray*)arr forKey:(NSString*)key;
- (NSArray*)getSubjectArrForKey:(NSString*)key;
- (BOOL)saveSubject:(JYSubjectsModel*)subModel forKey:(NSString*)key;
- (JYSubjectsModel*)getSubjectForKey:(NSString*)key;
//自定义对象及对象数组存取
- (BOOL)saveUserData:(JYUserModel*)model;
- (JYUserModel*)getUserData;
- (NSInteger)getUserId;
- (BOOL)isDataExist:(NSString*)dataName;
- (void)clearData;
@end
JYData.m
//
// JYData.m
// F2
//
// Created by zhangdan on 2018/4/12.
// Copyright © 2018年 szjy. All rights reserved.
//
#import "JYData.h"
@implementation JYData{
NSInteger dataId;
NSString * dirPath;
//涉及到多线程访问自定义对象情况下需要对访问文件过程加锁保证线程安全。
NSLock * lock;
//这里基本数据类型还用NSUserDefualts存储
NSUserDefaults * userDefaults;
}
+ (instancetype)shareData{
static JYData * data = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
data = [[JYData alloc] init];
});
return data;
}
- (id)init{
if (self = [super init]) {
dataId = 0;
lock = [[NSLock alloc]init];
userDefaults = [NSUserDefaults standardUserDefaults];
return self;
}
return nil;
}
//这里是根据不用用户就是不同手机号区分,用不用手机号创建不同的存储本地文件存储路径。此方法可以在获取验证码时调用,初始化这里的手机号。
- (BOOL)createDataID:(NSInteger)phoneNum{
dataId = phoneNum;
[self saveInteger:phoneNum forKey:@"dataId"];
if (dataId != 0) {
return YES;
}
NSLog(@"create user data fail!");
return NO;
}
- (NSInteger)getDataID{
if (dataId == 0) {
dataId = [self getIntegerForKey:@"dataId"];
}
return dataId;
}
- (BOOL)saveAvatar:(FUAvatar*)avatar forKey:(NSString*)key{
BOOL b= [NSKeyedArchiver archiveRootObject:avatar toFile:[self dataPath:key]];
return b;
}
- (FUAvatar*)getAvatarForKey:(NSString*)key;{
return [NSKeyedUnarchiver unarchiveObjectWithFile:[self dataPath:key]];
}
- (BOOL)saveAvatarArr:(NSArray*)arr forKey:(NSString*)key{
BOOL b= [NSKeyedArchiver archiveRootObject:arr toFile:[self dataPath:key]];
return b;
}
- (NSArray*)getAvatarArrForKey:(NSString*)key{
return [NSKeyedUnarchiver unarchiveObjectWithFile:[self dataPath:key]];
}
//自定义对象数组存储
- (BOOL)saveSubjectArr:(NSArray*)arr forKey:(NSString*)key{
BOOL b= [NSKeyedArchiver archiveRootObject:arr toFile:[self dataPath:key]];
return b;
}
//自定义对象数组获取
- (NSArray*)getSubjectArrForKey:(NSString*)key{
return [NSKeyedUnarchiver unarchiveObjectWithFile:[self dataPath:key]];
}
//自定义对象存储
- (BOOL)saveSubject:(JYSubjectsModel*)subModel forKey:(NSString*)key{
BOOL b= [NSKeyedArchiver archiveRootObject:subModel toFile:[self dataPath:key]];
return b;
}
//自定义对象获取
- (JYSubjectsModel*)getSubjectForKey:(NSString*)key{
return [NSKeyedUnarchiver unarchiveObjectWithFile:[self dataPath:key]];
}
- (void)saveInteger:(NSInteger)integer forKey:(NSString*)key{
[userDefaults setInteger:integer forKey:key];
[userDefaults synchronize];
}
- (NSInteger)getIntegerForKey:(NSString*)key{
return [userDefaults integerForKey:key];
}
- (BOOL)saveObject:(NSObject*)value forKey:(NSString*)key{
BOOL b= [NSKeyedArchiver archiveRootObject:value toFile:[self dataPath:key]];
return b;
}
- (id)getObjectForKey:(NSString*)key{
return [NSKeyedUnarchiver unarchiveObjectWithFile:[self dataPath:key]];
}
- (void)setURL:(NSURL*)URL forKey:(NSString*)key{
[userDefaults setURL:URL forKey:key];
[userDefaults synchronize];
}
- (NSURL*)getUrlForkey:(NSString*)key{
return [userDefaults URLForKey:key];
}
- (void)saveInt:(int)value forKey:(NSString*)key{
[userDefaults setInteger:value forKey:key];
[userDefaults synchronize];
}
- (int)getIntForKey:(NSString*)key{
return (int)[userDefaults integerForKey:key];
}
- (void)saveFloat:(float)value forKey:(NSString*)key{
[userDefaults setFloat:value forKey:key];
[userDefaults synchronize];
}
- (float)getFloat:(NSString*)key{
return [userDefaults floatForKey:key];
}
- (void)saveDouble:(double)value forKey:(NSString*)key{
[userDefaults setDouble:value forKey:key];
[userDefaults synchronize];
}
- (double)getDouble:(NSString*)key{
return [userDefaults doubleForKey:key];
}
- (void)saveBool:(BOOL)value forKey:(NSString*)key{
[userDefaults setBool:value forKey:key];
[userDefaults synchronize];
}
- (BOOL)getBool:(NSString*)key{
return [userDefaults boolForKey:key];
}
- (BOOL)saveUserData:(JYUserModel*)model{
//这里用户的信息数据是涉及到多线程访问的需要加线程锁
[lock lock];
BOOL b= [NSKeyedArchiver archiveRootObject:model toFile:[self dataPath:@"UserData"]];
[lock unlock];
return b;
}
- (JYUserModel*)getUserData{
[lock lock];
JYUserModel * model = [NSKeyedUnarchiver unarchiveObjectWithFile:[self dataPath:@"UserData"]];
[lock unlock];
return model;
}
- (NSInteger)getUserId
{
NSInteger uid = 0;
[lock lock];
JYUserModel * model = [NSKeyedUnarchiver unarchiveObjectWithFile:[self dataPath:@"UserData"]];
if (model) {
uid = model.userId;
}
[lock unlock];
return uid;
}
- (void)clearData{
NSString *dataIdPath = [NSString stringWithFormat:@"%ld",[self getDataID]];
NSString *path = [[[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingPathComponent:@"UserDataFiles"]stringByAppendingPathComponent:dataIdPath];
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager removeItemAtPath:path error:NULL]) {
NSLog(@"Removed successfully");
}
}
-(BOOL) isDataExist:(NSString*)dataName
{
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL result = [fileManager fileExistsAtPath:[self dataPath:dataName]];
NSLog(@"这个文件已经存在:%@",result?@"是的":@"不存在");
return result;
}
//获取存储路径,根据手机号对路径进行统一处理
- (NSString *)dataPath:(NSString *)file
{
NSString * tempPath = [file stringByAppendingString:@".data"];
NSString *dataIdPath = [NSString stringWithFormat:@"%ld",[self getDataID]];
NSString *path = [[[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingPathComponent:@"UserDataFiles"]stringByAppendingPathComponent:dataIdPath];
BOOL bo = [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
NSAssert(bo,@"创建目录失败");
NSString *result = [path stringByAppendingPathComponent:tempPath];
return result;
}
- (void)dealloc{
}
@end
说明一点,这里自定义对象是使用序列化方式存储到本地的需要在自定义对象当中重写(想要了解更多自行百度):
-(void) encodeWithCoder:(NSCoder *)encoder;
-(id) initWithCoder:(NSCoder *)decoder;
可以采用运行时方案,或者小码哥提供的方案,也是运行时但是一句代码搞定:
运行时:
@implementation Person
//解码
- (id)initWithCoder:(NSCoder *)coder
{
unsigned int iVarCount = 0;
Ivar *iVarList = class_copyIvarList([self class], &iVarCount);//取得变量列表,[self class]表示对自身类进行操作
for (int i = 0; i < iVarCount; i++) {
Ivar var = *(iVarList + i);
const char * varName = ivar_getName(var);//取得变量名字,将作为key
NSString *key = [NSString stringWithUTF8String:varName];
//decode
id value = [coder decodeObjectForKey:key];//解码
if (value) {
[self setValue:value forKey:key];//使用KVC强制写入到对象中
}
}
free(iVarList);//记得释放内存
return self;
}
//编码
- (void)encodeWithCoder:(NSCoder *)coder
{
unsigned int varCount = 0;
Ivar *ivarList = class_copyIvarList([self class], &varCount);
for (int i = 0; i < varCount; i++) {
Ivar var = *(ivarList + i);
const char *varName = ivar_getName(var);
NSString *key = [NSString stringWithUTF8String:varName];
id varValue = [self valueForKey:key];//使用KVC获取key对应的变量值
if (varValue) {
[coder encodeObject:varValue forKey:key];
}
}
free(ivarList);
}
小码哥方案(需要工程中导入MJextension):
当然大家也可以用数据库来封装这个存储工具,但是对外接口和封装思路大同小异,都是这样的。