iOS本地数据存储

2019-04-13 11:00:14 正式开始写简书,为了记录自己的学习经历,同时也分享自己的学习成果。当然有不对的地方非常欢迎大家提出,这样既能提高自己,也能防止误导别人╮( ̄▽ ̄)╭

OK,进入正题:

1.UserDefualt

最简单的数据存储方式了,直接上代码

    //UserDefualt
    NSMutableArray *mutArr = [[NSMutableArray alloc] initWithObjects:@"1", @"2", nil];
    NSArray *arr = [NSArray array];
    //1.UserDefualt存储数据
    [[NSUserDefaults standardUserDefaults] setObject:mutArr forKey:@"myData"];
    arr = [[NSUserDefaults standardUserDefaults] valueForKey:@"myData"];
    NSLog(@"arr = %@ \n", arr);
    
    [mutArr addObject:@"3"];
    [[NSUserDefaults standardUserDefaults] setObject:mutArr forKey:@"myData"];
    arr = [[NSUserDefaults standardUserDefaults] valueForKey:@"myData"];
    NSLog(@"arr = %@ \n", arr);

2.操作plist文件

对plist文件操作:需要获取文件存储路径后创建.plist文件,之后用系统提供的NSFileManager对文件进行操作,文件可以存在系统沙盒目录下的Document或者Cache文件,这里选择Document。

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"testLocalStorageData.plist"];
    NSLog(@"path = %@ \n", path);
    NSFileManager *fm = [NSFileManager defaultManager];
    [fm createFileAtPath:path contents:nil attributes:nil];
    //写入
    NSDictionary *dic = @{@"value1":@"key1", @"value2":@"key2"};
    [dic writeToFile:path atomically:YES];
    //读出
    NSDictionary *dicc = [NSDictionary dictionaryWithContentsOfFile:path];
    NSLog(@"dicc = %@ \n", dicc);

3.解归档

解归档能够存储对象数据,需要实现<NSCoding>或者<NSSecureCoding>协议,后者有一定加密措施。
.h文件

@interface TestClass : NSObject <NSSecureCoding> //解归档遵守NSCoding协议

.m文件

#pragma mark -NSSecureCoding方法实现
- (void)encodeWithCoder:(nonnull NSCoder *)aCoder {
    [aCoder encodeObject:self.test1 forKey:@"test1"];
    [aCoder encodeObject:self.test2 forKey:@"test2"];
    [aCoder encodeObject:self.test3 forKey:@"test3"];
    
}

- (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder {
    if (self == [super init]) {
        self.test1 = [aDecoder decodeObjectForKey:@"test1"];
        self.test2 = [aDecoder decodeObjectForKey:@"test2"];
        self.test3 = [aDecoder decodeObjectForKey:@"test3"];
    }
    return self;
}
//加密协议需要实现下面的方法
+ (BOOL)supportsSecureCoding {
    return YES;
}

使用:

    TestClass *myclass = [TestClass new];
    myclass.test1 = @"123";
    myclass.test2 = @"456";
    myclass.test3 = @"789";
    NSLog(@"myclass = %@", myclass.test1);
    NSString *archPath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
    NSString *archFilePath = [archPath stringByAppendingPathComponent:@"archData.data"];
    NSLog(@"----------%@", NSStringFromClass(myclass.class));
    NSError *error;
    //iOS12.0弃用
    //[NSKeyedArchiver archiveRootObject:myclass toFile:archFilePath];
    //归档
    NSData *archData = [NSKeyedArchiver archivedDataWithRootObject:myclass requiringSecureCoding:YES error:&error];
    NSLog(@"archData = %@", archData);
    if (error) {
        NSLog(@"archError : %@", error);
    }else{
        [archData writeToFile:archFilePath atomically:YES];
    }
    //解档
    NSData *unarch = [[NSData alloc] initWithContentsOfFile:archFilePath];
    TestClass *content = [NSKeyedUnarchiver unarchivedObjectOfClass:NSClassFromString(@"TestClass") fromData:unarch error:&error];
    if (error){
        NSLog(@"unarchError->%@", error);
    }else{
        NSLog(@"content = %@", content.test1);
    }

4.CoreData

用来存储数据形态更复杂的数据,首先创建.xcdatamodeld文件,具体步骤:NewFile->DataModel->名字->创建。
CoreData.png

封装CoreData方法为JCCoreDataManager

#import "JCCoreDataManager.h"

#define JC_CHECK_NSSTRING(str) ((str == nil) || ([str isEqualToString: @""]) || (str == NULL) || ([str isKindOfClass:[NSNull class]]))

@interface JCCoreDataManager(){
    NSString *path;
    NSString *dbFolderPath;
    
    NSError *error;
}

/**
 数据模型
 */
@property (nonatomic, strong) NSManagedObjectModel *objectModel;

/**
 管理数据的对象
 */
@property (nonatomic, strong) NSManagedObjectContext *objectContext;

/**
 持久化数据
 */
@property (nonatomic, strong) NSPersistentStoreCoordinator *coordinator;

@end

@implementation JCCoreDataManager

static JCCoreDataManager *manager = nil;

#pragma mark - 单例
+ (instancetype)sharedInstanceManager{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[JCCoreDataManager alloc] init];
    });
    return manager;
}


- (instancetype)init
{
    self = [super init];
    if (self) {
        //文件路径
        path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
        dbFolderPath = [path stringByAppendingPathComponent:@"CoreData"];
        
        NSError *error;
        //创建托管对象模型
        NSURL *url = [[NSBundle mainBundle] URLForResource:@"TestModel" withExtension:@"momd"];
        _objectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:url];
        //创建持久化协调器
        _coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:_objectModel];
        //创建本地数据库文件
        [_coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[self dbPath] options:nil error:&error];
        //创建托管对象上下文
        _objectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
        [_objectContext setPersistentStoreCoordinator:_coordinator];
    }
    return self;
}

/**
 获取数据库路径

 @return NSURL
 */
- (NSURL *)dbPath {
    NSError *error = nil;
    if (![self checkPathExist]) {
        [[NSFileManager defaultManager] createDirectoryAtPath:dbFolderPath withIntermediateDirectories:YES attributes:nil error:&error];
    }
    if (error){
        NSLog(@"创建CoreManager文件失败,error---->%@ \n", error);
        return nil;
    }
    NSURL *dbUrl = [[NSURL fileURLWithPath:dbFolderPath] URLByAppendingPathComponent:@"myDB.sqlite"];
    return dbUrl;
    
}

-(BOOL) checkPathExist{
    return [[NSFileManager defaultManager] fileExistsAtPath:dbFolderPath];
}

#pragma mark - 删除数据库
+ (NSString *)deleteCoreData{
    NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    NSString *fileFolderPath = [documentPath stringByAppendingPathComponent:@"CoreData"];
    NSError *error;
    if ([[NSFileManager defaultManager] fileExistsAtPath:fileFolderPath]){
        [[NSFileManager defaultManager] removeItemAtPath:fileFolderPath error:&error];
    }else{
        return @"没有数据,请先创建";
    }
    if (error){
        return [NSString stringWithFormat:@"删除失败,error--->%@", error];
    }
    return @"删除成功";
    
}

//=============数据库操作===============//
#pragma mark -获取数据模型
+ (NSManagedObject *)getManagedObjectWithEntityName:(NSString *)entityName{
    NSManagedObject *managedObject = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:[JCCoreDataManager sharedInstanceManager].objectContext];
    return managedObject;
}
#pragma mark -存储数据
+ (NSString *)save{
    JCCoreDataManager *manager = [JCCoreDataManager sharedInstanceManager];
    if (![manager checkPathExist]) {
        //manager = [[JCCoreDataManager alloc] init];
        [manager.coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[manager dbPath] options:nil error:nil];
    }
    NSError *saveError = nil;
    if ([manager.objectContext save:&saveError]) {
        return @"存储成功";
    }else{
        return [NSString stringWithFormat:@"存储失败,error->%@", saveError];
    };
}

#pragma mark -更新数据
+ (BOOL)updateManagedObject:(NSManagedObject *)managedObject{
    [[JCCoreDataManager sharedInstanceManager].objectContext refreshObject:managedObject mergeChanges:YES];
    return [JCCoreDataManager save];
}

#pragma mark -查找数据

+ (NSArray *)searchCoreDataWithEntityName:(NSString *)entityName andAttribute:(NSString *)attribute andSelectName:(NSString *)searchName sorting:(NSString *)sortAttribute isAsending:(BOOL)isAsending{
    NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:[JCCoreDataManager sharedInstanceManager].objectContext];
    //创建fetch请求
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    fetchRequest.entity = entity;
    //一次获取全部数据
    [fetchRequest setFetchBatchSize:0];
    NSSortDescriptor *nameDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
    NSSortDescriptor *ageDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:YES];
    NSSortDescriptor *bloodTypeDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"bloodType" ascending:YES];
    if (JC_CHECK_NSSTRING(sortAttribute) || ([sortAttribute isEqualToString:@"name"])) {
//        NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:sortAttribute ascending:isAsending];
        fetchRequest.sortDescriptors = @[nameDescriptor, ageDescriptor, bloodTypeDescriptor];
    }else if ([sortAttribute isEqualToString:@"age"]){
        fetchRequest.sortDescriptors = @[ageDescriptor, nameDescriptor, bloodTypeDescriptor];
    }else{
        fetchRequest.sortDescriptors = @[bloodTypeDescriptor, nameDescriptor, ageDescriptor];
    }
    if (!JC_CHECK_NSSTRING(attribute) && !JC_CHECK_NSSTRING(searchName)) {
        //查找某个属性的值包含某个字符串
        //%K 属性的值     %@ 字符串     ==
        fetchRequest.predicate = [NSPredicate predicateWithFormat:@"%K CONTAINS[cd] %@", attribute, searchName];
    }
    NSFetchedResultsController *fetchController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[JCCoreDataManager sharedInstanceManager].objectContext sectionNameKeyPath:nil cacheName:nil];
    NSError *error;
    if ([fetchController performFetch:&error]){
        return [fetchController fetchedObjects];
    }else{
        NSLog(@"%@", error);
        return @[];
    }
    
}

#pragma mark -删除数据
+ (NSString *)deleteWithEntityName:(NSString *)entityName andAttribute:(NSString *)attribute andSearchName:(NSString *)searchName{
    //没有删除条件
    if (JC_CHECK_NSSTRING(attribute) || JC_CHECK_NSSTRING(searchName)) {
        return @"没有删除条件或条件不完整";
    }
    //查找
    NSArray *arr = [JCCoreDataManager searchCoreDataWithEntityName:entityName andAttribute:attribute andSelectName:searchName sorting:attribute isAsending:YES];
    if (arr.count == 0)
        return @"没有找到数据";
    if (arr.count>0) {
        //删除
        for (NSManagedObject *object in arr) {
            [[JCCoreDataManager sharedInstanceManager].objectContext deleteObject:object];
        }
    }
    //存储数据
    [JCCoreDataManager save];
    return @"删除成功";
    
}

@end

数据处理和创建都只针对JCStudentModel,后面会补充相关数据的创建、关联、查找、删除。
创建数据(10个随机数据为例)

    for (int i = 0; i<10; i++) {
        JCStudentModel *studentModel = (JCStudentModel *)[JCCoreDataManager getManagedObjectWithEntityName:NSStringFromClass([JCStudentModel class])];
        uint32_t r = arc4random_uniform(99)+1;
        studentModel.name = [NSString stringWithFormat:@"student%@", r<10?[NSString stringWithFormat:@"0%u", r]:[NSString stringWithFormat:@"%u", r]];
        studentModel.age = arc4random_uniform(8)+10;
        studentModel.bloodType = arc4random_uniform(101)>50?@"A":@"B";
       
    }
    NSString *ans = [JCCoreDataManager save];

其他都只要调用一句即可:

//删除所有数据
[JCCoreDataManager deleteCoreData];
//条件查找
NSArray *a = [JCCoreDataManager searchCoreDataWithEntityName:NSStringFromClass([JCStudentModel class]) andAttribute:attribute  andSelectName:selectName sorting:sortAttribute isAsending:YES];
//条件删除
[JCCoreDataManager deleteWithEntityName:NSStringFromClass([JCStudentModel class]) andAttribute:attribute andSearchName:_keyWordsTextField.text];

目前就这些,欢迎大家批评指出不足:)

需要源码的请访问:https://github.com/daobao777/testLocalStorage

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容