美文网首页iOS OC
iOS 之 FMDB、CoreData、Plist、NSUse

iOS 之 FMDB、CoreData、Plist、NSUse

作者: 小强七号 | 来源:发表于2016-06-23 13:21 被阅读644次

    简述

    数据储存可以分为数据结构和储存方式。数据结构就是数据存在的的形式。例如 NSDictionnary、NSArray、NSSet等这些简单的对象,也有像CoreData那样的关系模型。储存方式在机器内则分为两种:1、内存;2、闪存。内存存储是临时的,但是运行速率非常快,闪存则是一种持久化存储,效率非常低。我们常说的归档就是将内存中的数据转移到闪存就行持久化保存。我们只有把内存和闪存结合起来进行操作才算完整的数据储存方案。盗图来说明:

    1.png

    常见方式

    iOS中常用的有:SQLite、CoreData、Plist、NSUserDefault。

    1. NSUserDefault: 用于储存配置信息
    2. SQLite: 主要用来储存数量较多的小型数据
    3. CoreData: 类似SQLite,但没SQLite那么灵活
    4. Plist: 用于存储图像、音频等大体积数据

    NSUserDefault

    1. 常规储存
      NSUserDefault可以看做为APP的一个全局单例,整个APP中只有一个实例对象,可以用于永久保存数据,非常容易操作。它支持储存的数据类型有:NSNumber、NSString、NSDictionary、NSArray、NSDate、BOOL。他的数据存储是通过key--value一一对应的(key必须唯一);

    2. 存储自定义对象
      储存小数量的自定义数据可以用NSUserDefault,但是这个自定义数据必须实现归档协议,不然会存不进去,只有转化成NSData类型才能通过NSUserDefault储存,如果是多个自定义数据可以添加到数组中,然后归档存储到NSUserDefault中。

    归档 解档
    //归档
    -(void)encodeWithCoder:(NSCoder *)aCoder{
        unsigned int count;
        objc_property_t *properties = class_copyPropertyList([self class], &count);
        for (int i = 0; i < count; i++) {
            const char * propertyCsString = property_getName(properties[i]);
            NSString   * propertyName  =  [NSString stringWithCString:propertyCsString encoding:NSUTF8StringEncoding];
            id           propertyValue =  [self valueForKey:propertyName];
            [aCoder encodeObject:propertyValue forKey:propertyName];
        }
        free(properties);
    }
    
    //解档
    -(instancetype)initWithCoder:(NSCoder *)aDecoder{
        self = [super init];
        if (self) {
            unsigned int count;
            objc_property_t *properties = class_copyPropertyList([self class], &count);
            for (int i = 0; i < count; i++) {
                const char *property_csNam = property_getName(properties[i]);
                NSString   *p_key = [NSString stringWithCString:property_csNam encoding:NSUTF8StringEncoding];
                id value = [aDecoder decodeObjectForKey:p_key];   
                [self setValue:value forKey:p_key];
            }   
            free(properties);
        } 
    return self
    } 
    
    
     ///copy 协议
    -(id)copyWithZone:(NSZone *)zone{
        StudentModel *s_model = [[self copyWithZone:zone] init];
        unsigned int count;
        objc_property_t *properties = class_copyPropertyList([self class], &count);
        for (int i = 0; i < count; i++) {
            const char *propertyCS = property_getName(properties[i]);
            NSString *p_key = [NSString stringWithCString:propertyCS encoding:NSUTF8StringEncoding];
            id p_value = [self valueForKey:p_key];
            [s_model setValue:p_value forKey:p_key];
        }
        free(properties);
        return s_model;
    }  
      //存储自定义对象
      StudentModel *s_model = [[StudentModel alloc] init];
        s_model.s_name = @"xiaoqiang";
        s_model.s_id = @"22";
        s_model.s_password = @"123456";
        NSData *data = [NSKeyedArchiver archivedDataWithRootObject:s_model];
        [u_default setObject:data forKey:@"s_student"];
        [u_default synchronize];
        NSData *rachiverData = [u_default objectForKey:@"s_student"];
        StudentModel *model = [NSKeyedUnarchiver unarchiveObjectWithData:rachiverData];
        NSLog(@"\n name is %@ \n id is %@ \n password is %@",model.s_name,model.s_id,model.s_password);  
    

    Plist

    沙盒

    机制:

    iOS沙盒机制就是指该APP只能访问自己的沙盒目录下的文件,不能访问其他APP的沙盒文件,主要用来保存图像、图标、声音、属性列表,文本等,不过iOS 8后新开放了几个固定系统区域的扩展机制extension,它可以一定程度上解决APP之间的通信限制。

    目录
    1. Documents
      Documents主要用来保存APP运行时需要持久化保存的数据,该目录会被iTunes同步时备份

    2. Library
      2.1 . Caches
      Caches是用来保存APP运行时需要持久化储存的数据,但不会被iTunes同步,所以该目录适合保存一些体积大而且不需要备份的数据

      2.2. Prefrernces
      PreFrernces是用来保存应用偏好设置的,iOS的设置应用会在该目录中查找应用设置的信息,也会被iTunes同步到备份

    3. tmp
      保存APP运行时的临时数据,关闭APP后会被自动删除

    获取目录方式
    拼接获取:
     NSString *homePath = NSHomeDirectory();
     NSString *path = [homePath stringByAppendingPathComponent:@"Documents"];
     return [path stringByAppendingPathComponent:suffix]; `   
    打印得到的路径:/var/mobile/Containers/Data/Application/0FB7706E-625C-482C-B1DE-DDD241BB3220/Documents/test.plist
    
    利用NSSearchPathForDirectoriesInDomains函数获得Documents目录:
     NSArray *pathArr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *path = pathArr[0];
        return [path stringByAppendingPathComponent:suffix];
    打印得到的路径:`  /var/mobile/Containers/Data/Application/0FB7706E-625C-482C-B1DE-DDD241BB3220/Documents/test.plist
    

    第一个参数为代表文件路径 一般用到NSDocumentDirectory或者NSCachesDirectory 第二个参数一般为NSUserDomainMask,第三个参数代表是否打开一般为YES,上面PathArr 一般只能或得一个元素,

    补充

    获取沙盒tmp目录的方法:

     NSString *tmp = NSTemporaryDirectory();
    

    获取沙盒caches目录方法:

    NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
    

    获取应用沙盒preference目录的方法:

     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    

    言归正传继续plist操作笔记 plist储存的数据:array,dictionary,string,bool,date,data这几种类型,如果要存储自定义的也要实现归档协议然后转换成NSData类型储存,plist主要用来存储大文件。

     NSString *path = [self getPlistLibraryWithSuffix:@"test.plist"];
    
        NSMutableArray *stu_array = [NSMutableArray new];
        
        for (int i = 0; i < 10; i ++) {
            
            StudentModel *s_model = [StudentModel new];
            
            s_model.s_name = [NSString stringWithFormat:@"name%d",i];
            s_model.s_id = [NSString stringWithFormat:@"%d",100 + i];
            s_model.s_password = @"123456";
            [stu_array addObject:s_model];
        }
    ///写入
        NSData *archiverData = [NSKeyedArchiver archivedDataWithRootObject:stu_array];
        BOOL isSuc = [archiverData writeToFile:path atomically:YES];
    //  BOOL isSuc = [NSKeyedArchiver archiveRootObject:stu_array toFile:path];
        NSLog(@"%d",isSuc);
     
      ///读取
        NSData *unarchiverData = [NSData dataWithContentsOfFile:path];
        NSArray *unArchiverArr = [NSKeyedUnarchiver unarchiveObjectWithData:unarchiverData];
    //  NSArray *unArchiverArr = [NSKeyedUnarchiver unarchiveObjectWithFile:path];    
        NSLog(@"%@==",unArchiverArr);
    

    SQLite:

    iOS的SDK有SQLite的库,我们可以自建SQLite数据库,SQLite每次写入数据都会产生IO消耗,把数据归档到相应的文件。其实SQLite也跟NSUserDefaults差不多,适合储存基础类型的小数据,不过它更适合存储大量的数据,类似聊天记录这样的数据查询和储存。SQLite的操作比较复杂,因为它不是面向对象的,我们用起来很不习惯,但是我们可以用第三发框架FMDB,在工程中pod FMDB 进来。

    FMDB:

    1. FMDataBase:它主要用来执行SQL语句,但是它线程不安全的
    2. FMResult 用于查询结果
    3. FMDatabaseQueue 多余多线程查询或者更新 它是线程安全的

    FMDB几个主要的方法

    FMDB中除了查询之外都可以称作为更新,create、delete,update、insert、drop,使用executeUpdate:方法更新

    更新
    - (BOOL)executeUpdate:(NSString*)sql, ...
    - (BOOL)executeUpdateWithFormat:(NSString*)format, ...
    - (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments
    - (BOOL)executeUpdate:(NSString*)sql withParameterDictionary:(NSDictionary *)arguments;
    
    查询
    - (FMResultSet *)executeQuery:(NSString*)sql, ...
    - (FMResultSet *)executeQueryWithFormat:(NSString*)format, ...
    - (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments
    
    SQL语句
    1. 创建表语句
      create table if not exists StudentTab(numberID integer primary key not NULL ,name text,headImage blob,scroll real)

    这表示如果不存在StudentTab,则创建一个NumberID自动增加的的序号值,name是文本字符串类型,head为二进制类型,scroll为浮点型类型

    1. 插入语句
    insert into Student(name,headImage,scroll)  values (?,?,?)
    insert into Student values (:name,:headImage,:scorll);
    insert into Student(name,headImage,scroll) values('%@','%@','%lf') 
    //这三句等价
    
    1. 更新语句
    update Student set name = ? where scoll = ?
    
    1. 删除语句
    delete  from Student where name = ?
    drop table if exists Student
    
    1. 查询语句
    select * from Student where name = ?
    

    特殊用法:
    如果你要保存的参数个数未知或者数量较多 我们可以用一下这些方法 给让你感受到很好的体验

     - (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments
     - (BOOL)executeUpdate:(NSString*)sql withParameterDictionary:(NSDictionary *)arguments;
    

    数据库的事务也很好用 inDeferredTransaction

    CoreData

    1. NSManagedObjectModel(被管理的对象模型)相当于实体,但它也包含了实体间的关系,
    2. NSManagedObjectContext(被管理的对象上下文)操作的作用有:插入数据、查询、更新、删除
    3. NSPersistentStoreCoordinator(持久化储存助理)它充当这与数据库连接的角色
    4. NSPredicate(相当于查询条件)
    5. NSFetchRequest(获取数据的请求)
    6. NSEntityDescription(实体结构)
    7. NSFetchedResultsController:监听数据变化 实现代理 当数据发生变化会尽代理
      NSFetchRequest *result = [NSFetchRequest fetchRequestWithEntityName:@"User"];`
      NSSortDescriptor * desciptor = [NSSortDescriptor sortDescriptorWithKey:@"u_name" ascending:YES];
        
        [result setSortDescriptors:@[desciptor]];
    
        NSManagedObjectContext *context = self.manager.mainManagedObjectContext;
        
        self.userFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:result managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
        self.userFetchedResultsController.delegate = self;  
    
    版本迁移

    coredata需要注意版本更新数据迁移处理 一般加自动迁移处理

    //自动迁移
     NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                              [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                              [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
         abort();
     }
     return _persistentStoreCoordinator;
    }  
    
    插入
    User *user = (User *)[NSEntityDescription insertNewObjectForEntityForName:@"User" inManagedObjectContext:self.manager.mainManagedObjectContext];
        [user setU_age:@"26"];
        [user setU_name:@"liu"];
        [user setU_sex:@"1"];
        NSError *error ;
       BOOL isSuc =[self.manager.mainManagedObjectContext save:&error];
    
    删除
      NSFetchRequest *result = [[NSFetchRequest alloc] init];
        NSEntityDescription *user = [NSEntityDescription entityForName:@"User" inManagedObjectContext:self.manager.mainManagedObjectContext];
        [result setEntity:user];
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"u_name = %@",@"liu"];
        [result setPredicate:predicate];    
        NSError *error = nil;
        NSArray *arr = [self.manager.mainManagedObjectContext executeFetchRequest:result error:&error]; 
        if (arr.count == 0) {
            NSLog(@"error is %@",error);
        }else{
            for (User *temp in arr) {
                [self.manager.mainManagedObjectContext deleteObject:temp];
            }
        }
        [self.manager.mainManagedObjectContext saveAndWait:YES error:&error];
    
    更新:
     NSFetchRequest *result = [[NSFetchRequest alloc] init];    
        NSEntityDescription *user = [NSEntityDescription entityForName:@"User" inManagedObjectContext:self.manager.mainManagedObjectContext];
        [result setEntity:user];
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"u_name = %@",@"liu"];
        [result setPredicate:predicate];
        NSError *erro = nil;
        NSArray *arr = [self.manager.mainManagedObjectContext executeFetchRequest:result error:&erro];
        if (arr.count == 0) {
            NSLog(@"%@ error ",erro);
        }else{
            for (User *tempUser in arr) {
                tempUser.u_age = @"18";
            }
        }
        [self.manager.mainManagedObjectContext save:&erro];
    
    查询
      NSFetchRequest *result = [[NSFetchRequest alloc] init];
        NSEntityDescription *user = [NSEntityDescription entityForName:@"User" inManagedObjectContext:self.manager.mainManagedObjectContext];
        
        [result setEntity:user];
        
        NSError *error ;
        
        NSMutableArray *arr = [[self.manager.mainManagedObjectContext executeFetchRequest:result error:&error] mutableCopy];
        
        if (arr.count == 0) {
            
            NSLog(@"error is %@",error);
        }
        else{
            
            for (User *tempUser in arr) {
                
                NSLog(@"%@==%@===%@",tempUser.u_name,tempUser.u_age,tempUser.u_sex);
            }
        }
    
    线程安全处理
    +(id) instanceChildManagedObjectContext {
        NSManagedObjectContext *context = nil;
        if ([NSThread isMainThread]) {
            context = [[CoreDataManager sharedCoreDataManager] mainManagedObjectContext];
        } else {
            context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
            context.parentContext = [[CoreDataManager sharedCoreDataManager] mainManagedObjectContext];
        }
        return context;
    }
    

    相关文章

      网友评论

      • iOS_小胜:我怎么感觉你内存和闪存说反了...

      本文标题: iOS 之 FMDB、CoreData、Plist、NSUse

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