美文网首页
iOS本地数据存储

iOS本地数据存储

作者: daobao777 | 来源:发表于2019-04-13 13:58 被阅读0次

    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

    相关文章

      网友评论

          本文标题:iOS本地数据存储

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