数据库和持久化方案

常规持久化方案

属性列表(Plist)

 键值进行存储,不能存储对象。对象需要序列化编码才能写入文件。
 `NSAarry`,`NSDictionary`,`NSData`,`NSString`等类型可以直接调用`writeToFile`方法把数据存储到`plist`文件中。
 但是数组中的元素或者字典中的元素必须是下面的七种类型:`NSData`,`NSArray`,`NSDictionary`,`NSDate`,`NSString`,`NSNumber`,`Boolean`。
`NSUserDefault`本质上也是存储到`plist`文件中,所以存入`NSUserDefault`当中的对象也应该满足以上七种类型。
 适用于应用与少量数据存储,比如登陆的用户信息,应用程序配置信息等。
plist存储的写入:
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];  
NSString *completePath = [documentPath stringByAppendingPathComponent:@"names"];  
[arr writeToFile:completePath atomically:YES]; 
plist存储的读取:
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];  
    NSString *completePath = [documentPath stringByAppendingPathComponent:@"names"];  
    NSArray *resultArr = [NSArray arrayWithContentsOfFile:completePath];  
    NSLog(@"%@",resultArr); 
偏好设置存储(NSUserDefaults)
偏好设置一般存储一些像账号密码之类的东西,写入到Preference文件夹.
偏好设置存储写入:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];  
[userDefaults setValue:@"China" forKey:@"china"];  
[userDefaults setInteger:1 forKey:@"1"];  
[userDefaults setBool:YES forKey:@"yes"];  
//立即存储  
[userDefaults synchronize];  
偏好设置存储读取:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];  
NSString *china = [defaults valueForKey:@"china"];  
NSInteger number = [defaults integerForKey:@"1"];  
BOOL bu = [defaults boolForKey:@"yes"];  
NSLog(@"%@--%d,%ld",china,bu,number); 
归档存储
归档存储一般存储自定义对象,并且自定义对象需要遵守NSCoding协议.
首先创建一个自定义对象MCPerson,并且让其遵守NSCoding协议.
#import <Foundation/Foundation.h>  

@interface MCPerson : NSObject<NSCoding>  
@property(nonatomic,copy)NSString *name;  
@property(nonatomic,copy)NSString *phone;  
@end  
在.m文件中实现NSCoding协议的两个方法.
#import "MCPerson.h"  

@implementation MCPerson  
//编码  
- (void)encodeWithCoder:(NSCoder *)aCoder{  
    [aCoder encodeObject:self.name forKey:@"name"];  
    [aCoder encodeObject:self.phone forKey:@"phone"];  
}  
//解码  
- (instancetype)initWithCoder:(NSCoder *)aDecoder{  
    if (self = [super init]) {  
      self.name = [aDecoder decodeObjectForKey:@"name"];  
      self.phone = [aDecoder decodeObjectForKey:@"phone"];  
    }  
    return self;  
}  
@end  
注意事项:如果父类也遵守了NSCoding协议,那么需要在encodeWithCoder:方法中加上[super encodeWithCoder:aCoder].在initWithCoder:方法中将self = [super init]写成self = [super initWithCoder:aDecoder].确保继承自父类的实例变量也能被解码和解码.
归档存储的写入:
MCPerson *person = [[MCPerson alloc]init];  
person.name = @"jack";  
person.phone = @"12425626236";  
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];  
NSString *completePath = [documentPath stringByAppendingPathComponent:@"person"];  
[NSKeyedArchiver archiveRootObject:person toFile:completePath];  
归档存储的读取:
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];  
NSString *completePath = [documentPath stringByAppendingPathComponent:@"person"];  
MCPerson *person = [NSKeyedUnarchiver unarchiveObjectWithFile:completePath];  
NSLog(@"%@--%@",person.name,person.phone);  

对象序列化:

最终也是存为属性列表文件,如果程序中,需要存储对象属性的时候,直接存储对象比较方便,例如有一个设置类,我们可以把设置类的对象直接存储,就没必要再把里面的每一个属性单独存到文件中,对象序列化是将一个实现了NSCoding协议的对象,通过序列化(NSKeyedArchiver)的形式,将对象中的属性抽取出来,转换成二进制流,也就是NSData,NSData可以选择writeToFile或者存储到NSUserdefault中,必须实现两个方法encodeWithCoder,initWithCoder。对象NSData。
      NSObject<NSCoding>=====(NSKeyedArchiver)=====>>NSData=====(writeToFile)=====>>File
                                                                                                       ||
                                                                                                       ||
                                                                                                       ||
                                                                                                       ||
                                                                                               NSUserDefault

sqlite3使用

SQLite简介

SQLite,是一款轻型的数据库也叫做关系型数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。

SQLite3

在XCode工程中,打开targets,在Build Phases下导入Libsqlite.tbd,在需要使用sqlite3的位置导入头文件即可.

生成路径
+(NSString *)path{

NSArray *documentArr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

NSString *documentPath = [documentArr firstObject];
// crylown.db 为数据库的名字
NSString *path = [NSString stringWithFormat:@"%@/crylown.db",documentPath];

return path;
}
创建/打开数据库
sqlite3 *database;

int databaseResult = sqlite3_open([[self path] UTF8String], &database);

if (databaseResult != SQLITE_OK) {

    NSLog(@"创建/打开数据库失败,%d",databaseResult);
}
创建表
char *error;

//    建表格式: create table if not exists 表名 (列名 类型,....)    注: 如需生成默认增加的id: id integer primary key autoincrement
    const char *createSQL = "create table if not exists list(id integer primary key autoincrement,name char,sex char)";

    int tableResult = sqlite3_exec(database, createSQL, NULL, NULL, &error);

    if (tableResult != SQLITE_OK) {

        NSLog(@"创建表失败:%s",error);
    }
添加数据
// 对SQL语句执行预编译
int sqlite3_prepare(sqlite3 *db, const char *sql,int byte,sqlite3_stmt **stmt,const char **tail)

1.db代表打开的数据库连接
2.sql代表的sql语句
3.byte代表SQL语句的最大长度
4.传出参数,指向预编译SQL语句产生的sqlite3_stmt
5.指向SQL语句中未使用的部分
int sqlite3_prapare_v2()版本,代表该函数的最新版本。

 //   添加
    //   sql语句格式: insert into 表名 (列名)values(值)
        const char *insertSQL = "insert into haha (name,sex)values('iosRunner','male')";
        int insertResult = sqlite3_prepare_v2(database, insertSQL, -1, &stmt, nil);

        if (insertResult != SQLITE_OK) {
            NSLog(@"添加失败,%d",insertResult); 
        }
        else{
    //           执行sql语句
            sqlite3_step(stmt);
        }
查找数据
//返回sqlite3_stmt(预编译SQL语句产生的结果)
const char* sqlite3_colum_int/text...(sqlite3_stmt *,int N)

根据结果返回的值的类型不同选择int/text等,N代表列名在表中的位置。

//    查找
//   sql语句格式: select 列名 from 表名 where 列名 = 参数       注:前面的列名为查询结果里所需要看到的 列名,后面的 列名 = 参数 用于判断删除哪条数据
     const char *searchSQL = "select id,name,sex from haha where name = 'puyun2'";
        int searchResult = sqlite3_prepare_v2(database, searchSQL, -1, &stmt, nil);
        if (searchResult != SQLITE_OK) {
            NSLog(@"查询失败,%d",searchResult); 
        }
        else{
            while (sqlite3_step(stmt) == SQLITE_ROW) {
            // 查询的结果可能不止一条,直到 sqlite3_step(stmt) != SQLITE_ROW,查询结束。
                int idWord = sqlite3_column_int(stmt, 0);
                char *nameWord = (char *) sqlite3_column_text(stmt, 1);
                char *sexWord = (char *)sqlite3_column_text(stmt, 2);
                NSLog(@"%d,%s,%s",idWord,nameWord,sexWord);
            }
        }
修改数据
 // 修改
       // sql语句格式: update 表名 set  列名 = 新参数 where 列名 = 参数   注:前面的 列名 = 新参数 是修改的值, 后面的 列名 = 参数 用于判断删除哪条数据
        const char *changeSQL = "update haha set name = 'buhao' where name = 'iosRunner'";

        int updateResult = sqlite3_prepare_v2(database, changeSQL, -1, &stmt, nil);

        if (updateResult != SQLITE_OK) {

            NSLog(@"修改失败,%d",updateResult);
        }
        else{

            sqlite3_step(stmt);
        }
删除数据
//        删除
//        sql语句格式: delete from 表名 where 列名 = 参数     注:后面的 列名 = 参数 用于判断删除哪条数据
        const char *deleteSQL = "delete from haha where name = 'iosRunner'";

        int deleteResult = sqlite3_prepare_v2(database, deleteSQL, -1, &stmt, nil);

        if (deleteResult != SQLITE_OK) {

            NSLog(@"删除失败,%d",deleteResult);

        }
        else{
            sqlite3_step(stmt);
        }
结束处理
//        销毁stmt,回收资源
        sqlite3_finalize(stmt);

//    关闭数据库
    sqlite3_close(database);
优缺点:

NSOutputStream,NSInputStream
适合大量,重复,有规律的数据存储,而且频繁的读取,删除,过滤数据,这种适合使用数据库。重用的增删改查语句,使用第三方库FMDB更好的处理数据。

CoreData:(以对象方式操作数据库)

CoreData简介

CoreData是一种OR-Mapping的思想,O代表对象Object,R代表relationship,Mapping代表映射,直译过来就是对象关系映射,其实就是把对象的属性和表中的字段自动映射,简化程序员的负担,以面向对象的方式操作数据库。

CoreData本质还是数据库,只不过使用起来更加面向对象,不关注二维的表结构,而是只需要关注对象,纯面向对象的数据操作方式。我们直接使用数据库的时候,如果向数据库中插入数据,一般是把一个对象的属性和数据库中某个表的字段一一对应,然后把对象的属性存储到具体的表字段中,取一条数据的时候,把表中的一行数据取出,同样需要再封装到对象的属性中,这样的方式有点繁琐,不面向对象。CoreData解决的问题就是不需要这个中间的转换过程,看起来是直接把对象存储进去,并且取出,不关心表的存在,实际内部已经帮你做好了映射关系。

Core Date实际上是对SQLite的封装,提供了更高级的持久化方式。在对数据库操作时,不需要使用sql语句,也就意味着即使不懂sql语句,也可以操作数据库中的数据。

CoreData中经常使用的类

NSManagedObjectContext管理对象上下文:相当于FMDB中的FMDatabase对象,我们对数据中的操作先存储到这个上下文中,然后把操作同步到数据库中。

NSManagedObject托管对象:相当于是对表中一行数据的封装。

NSEntityDescription实体描述:相当于在这个对象中定义了数据库中表的结构,比如包含哪些字段等。

NSPersistentStoreCoordinator持久化存储协调器:链接数据库的类,里面包含了数据库的位置,名称等,相当于文件管理器,帮我们创建数据库文件等。

NSMangedObjectModel托管对象模型:里面包含了数据库表,表之间关系的设计模型。其实这个对象里面包含的就是我们使用CoreData时,设计数据库模型Xcdatamodel文件中的信息。

CoreData的详解参见这儿

总结

最后说一下所有的本地持久化数据存储的本质都是写文件,而且只能存到沙盒文件中。沙盒机制是苹果的一项安全机制,本质就是系统给每个应用分配了一个文件夹来存储数据,而且每个应用只能访问分配给自己的那个文件夹,其他应用的文件夹是不能访问的。
沙盒中默认的三个文件夹(支持自己创建新的文件夹):
1、Documents:存储用户相关的数据(用户拍的视频,用户创作的图片,用户唱的歌曲,用户收藏的商品等等)。
2、Library:跟程序相关的数据(程序缓存,程序的配置文件等等)。
3、Temp:放临时文件,不需要永久存储的,比如下载的时候,需要存储到临时文件中,最终copy到Documents或Library中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值