IOS开发指南学习——数据持久化(属性列表、对象归档、SQLite)

本文介绍了iOS开发中的数据持久化方法,包括属性列表、对象归档和SQLite数据库。属性列表是简化版的XML,适合小数据存储;对象归档用于对象序列化,可能不适用于大量数据频繁读写;SQLite是关系型数据库,适用于更复杂的数据存储需求。文中还提及了如何在iOS应用中引入SQLite库并处理数据类型兼容性问题。
摘要由CSDN通过智能技术生成

对于任何一种语言来说,数据持久化都可以说是最重要、最实用的部分。

可以说任何一个程序都必须要涉及到数据的持久化,对于ios来说,数据的持久化主要有4种机制,分别为属性列表、对象归档、SQLite数据库和Core Data。其中的Core Data本质上也是通过SQLite存储的,只不过实用了ORM技术来实现。

首先要先知道一个概念,对于熟悉ios的人来说,应该都对document这个文件不陌生,在ios中,这个文件夹称为“沙箱目录”,任何一个程序安装完成后都会有这么一个文件夹产生,这是一个相对独立的文件夹,不同应用之间一般不能互相访问其他应用的沙箱目录。获取该目录的代码如下:

NSString* documentDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];

在数据的持久化中会经常使用到这个方法获取沙箱目录。

一、属性列表

在java开发中,对于小数据存储,我们会使用xml文件来存储并使用xml解析来获取数据,这是一个比较复杂的过程。而在ios中,属性列表,也是一种xml文件,但是ios对其进行大量的封装,使其使用起来非常的方便和简洁,该文件存储为plist文件。其使用过程中的核心语句如下:

#pragma mark --数据持久化
- (NSString*)applicationDocumentsDirectoryFile{
    //获取并返回属性列表文件的详细路径
    NSString* documentDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString* path = [documentDirectory stringByAppendingString:@"/NoteList.plist"];
    return path;
}

- (void)createEditableCopyOfDatabaseIfNeeded{
    NSFileManager* fileManager = [NSFileManager defaultManager];
    NSString* writableDBPath = [self applicationDocumentsDirectoryFile];
    //判断plist文件是否已经存在
    if (![fileManager fileExistsAtPath:writableDBPath]) {
        //获取资源目录
        NSString* defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:@"/NoteList.plist"];
        NSError* error;
        //将资源目录中的plist文件复制到Document文件夹中
        NSAssert([fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error], @"写入文件错误");
        NSLog(@"成功复制资源文件");
    }
}

- (NSMutableArray*)findAll{
    //获取plist文件详细路径
    NSString* path = [self applicationDocumentsDirectoryFile];
    //将plist文件中的数据存储到Array数组中
    NSMutableArray* array = [[NSMutableArray alloc] initWithContentsOfFile:path];
    NSMutableArray* data = [[NSMutableArray alloc] init];
    //创建日期格式类
    NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    //遍历Array数组
    for (NSDictionary* dict in array) {
        Note* note = [[Note alloc] init];
        NSDate* date = [dateFormatter dateFromString:[dict objectForKey:@"date"]];
        note.date = date;
        note.content = [dict objectForKey:@"content"];
        [data addObject:note];
    }
    return data;
}

- (int)create:(Note*)model{
    NSString* path = [self applicationDocumentsDirectoryFile];
    NSMutableArray* array = [[NSMutableArray alloc] initWithContentsOfFile:path];
    NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    //创建一个字典类型来存储note对象
    NSDictionary* dict = [NSDictionary dictionaryWithObjects:@[[dateFormatter stringFromDate:model.date],model.content] forKeys:@[@"date",@"content"]];
    //将创建的字典类型增加Array数组中
    [array addObject:dict];
    //将改变了的数组写入到plist文件中
    [array writeToFile:path atomically:YES];
    
    return 0;
}

二、对象归档

对象归档是一种将对象序列化为文件并进行存储的技术,对象归档不适合于大量数据的频繁读写,我目前还没有弄清楚这种持久化方式适用的地方,但也对其使用方式进行整理。

使用对象归档的对象Note必须能够归档,所以,Note类必须实现NSCoding协议,相关代码如下:

<pre name="code" class="objc">#import <Foundation/Foundation.h>

//实现NSCoding协议
@interface Note : NSObject<NSCoding>

@property(nonatomic,strong) NSDate* date;
@property(nonatomic,strong) NSString* content;

@end

#import "Note.h"

@implementation Note

@synthesize date,content;

- (void)encodeWithCoder:(NSCoder *)aCoder{
    //编码方法
    [aCoder encodeObject:date forKey:@"date"];
    [aCoder encodeObject:content forKey:@"content"];
}

-(id)initWithCoder:(NSCoder *)aDecoder{
    //反编码方法
    self.date = [aDecoder decodeObjectForKey:@"date"];
    self.content = [aDecoder decodeObjectForKey:@"content"];
    return self;
}

@end

 


操作过程中的核心代码如下:

<pre name="code" class="objc"><span style="font-family: Arial, Helvetica, sans-serif;">- (NSMutableArray*)findAll{</span>

    //获取归档文件的详细路径
    NSString* path = [self applicationDocumentsDirectoryFile];
    //实例化可变数组
    NSMutableArray* listData = [[NSMutableArray alloc] init];
    //从归档文件中读取字节数据
    NSData* theData = [NSData dataWithContentsOfFile:path];
    
    if ([theData length] > 0) {
        //实例化NSkeyedUnarchiver对象,并由该对象来反归档字节数据
        NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:theData];
        //反归档字节数组
        listData = [unarchiver decodeObjectForKey:@"ARCHIVE_KEY"];
        //完成反归档
        [unarchiver finishDecoding];
    }
    return listData;
}

 
- (int)modify:(Note*)model{
    //获取归档文件的详细路径
    NSString* path = [self applicationDocumentsDirectoryFile];
    NSMutableArray* array = [self findAll];
    
    for (Note* note in array) {
        if ([note.date isEqualToDate:model.date]) {
            note.content = model.content;
            //Data类封装了字节数据的缓存类,提供了读写数据的方法,这里实例化NSMutableData类
            NSMutableData* theData = [NSMutableData data];
            //实例化NSkeyedArchiver对象,并由该对象来将归档数据
            NSKeyedArchiver* archive = [[NSKeyedArchiver alloc] initForWritingWithMutableData:theData];
            //将Array对象编码到NSkeyedArchiver对象中
            [archive encodeObject:array forKey:@"ARCHIVE_KEY"];
            //完成编码
            [archive finishEncoding];
            //写入文件
            [theData writeToFile:path atomically:YES];
            return 0;
        }
    }
    return -1;
}

三、SQLite数据库

有过其他程序语言基础的人应该对SQLite数据库并不陌生,SQLite是用户嵌入式系统使用的关系型数据库,其使用方式与其他关系型数据库相似,在使用SQLite数据库进行数据持久化时,必须先在工程中引入SQLite3库。方法是,选择工程中的TARGET-->工程名-->Build Phases -->Link Binary With Libraries,点击左下方的”+“,选择libsqlite3.dylib或者libsqlite3.0.dylib,并点击”Add“完成添加,如图所示:


完成sqlite3库的导入后,就可以使用sqlite数据库进行开发了,需要注意的是,SQLite3函数是纯C语言函数,虽然objective-C中可以直接调用C语言函数,但是必须要注意两种语言之间的数据类型的兼容性问题,如NSString就是objective-C的数据类型,必须要转换为C语言数据类型char才可以正常使用。使用过程中用到核心代码如下:

#pragma mark --数据持久化
- (NSString*)applicationDocumentsDirectoryFile{
    //获取数据库文件的详细路径
    NSString* documentDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString* path = [documentDirectory stringByAppendingString:@"/NoteList.sqlite3"];
    return path;
}

- (void)createEditableCopyOfDatabaseIfNeeded{
    //获取数据库文件的详细目录并转换为char数据类型
    NSString* writableDBPath = [self applicationDocumentsDirectoryFile];
    const char* cpath = [writableDBPath UTF8String];
    //打开数据库,第一个参数为数据库文件完整路径,第二个sqlite3指针变量的地址
    if (sqlite3_open(cpath, &db) == SQLITE_OK) {
        NSLog(@"成功打开SQLite3");
        char* err;
        //使用sql语句创建Note表
        NSString* sql = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS Note(cdate TEXT PRIMARY KEY,content TEXT);"];
        const char* cSql = [sql UTF8String];
        //使用sqlite3_exec执行sql语句,其中,第三个参数为会掉函数,第四个参数为回调函数的参数
        if (sqlite3_exec(db, cSql, nil, nil, &err) != SQLITE_OK) {
            sqlite3_close(db);
            NSAssert(NO, @"建表失败");
        }else{
            NSLog(@"建表成功");
        }
    }else{
        //如果打开数据库失败,也必须要将数据库关闭
        NSAssert(NO, @"打开SQLite3失败");
        sqlite3_close(db);
    }
}

- (NSMutableArray*)findAll{
    NSString* path = [self applicationDocumentsDirectoryFile];
    const char* cPath = [path UTF8String];
    NSMutableArray* listData = [[NSMutableArray alloc] init];
    if (sqlite3_open(cPath, &db)) {
        sqlite3_close(db);
        NSAssert(NO, @"打开数据库失败");
    }else{
        NSString* sql = @"SELECT cdate,content FROM Note";
        const char* cSql = [sql UTF8String];
        //sqlite3_stmt是语句对象,通过它可以执行sql语句
        sqlite3_stmt* statement;
        //预处理过程,sqlite3_prepare_v2函数的第三个参数为sql语句的只付出长度,第五个参数为sql语句未执行的部分
        if (sqlite3_prepare_v2(db, cSql, -1, &statement, nil) == SQLITE_OK) {
            NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
            [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
            //使用sqlite3_step函数执行sql语句,当返回值为SQLITE_ROW时说明statement还有行没有被遍历
            while (sqlite3_step(statement) == SQLITE_ROW) {
                //取出该行的第一个数据并格式化为NSDate类型,数据的序号从0开始
                char* bufDate = (char*) sqlite3_column_text(statement, 0);
                NSString* strDate = [[NSString alloc] initWithUTF8String:bufDate];
                NSDate* date = [dateFormatter dateFromString:strDate];
                //取出该行的第二个数据并格式化为NSString类型
                char* bufContent = (char*) sqlite3_column_text(statement, 1);
                NSString* strContent = [[NSString alloc] initWithUTF8String:bufContent];
                Note* note = [[Note alloc] initWithDate:date content:strContent];
                [listData addObject:note];
            }
        }
        //关闭语句对象及数据库
        sqlite3_finalize(statement);
        sqlite3_close(db);
    }
    
   
    return listData;
}

- (int)create:(Note*)model{
    NSString* path = [self applicationDocumentsDirectoryFile];
    const char* cPath = [path UTF8String];
    
    if (sqlite3_open(cPath, &db) != SQLITE_OK) {
        NSAssert(NO, @"打开数据库失败");
        sqlite3_close(db);
    }else{
        NSString* sql = @"INSERT OR REPLACE INTO Note (cdate,content) VALUES (?,?)";
        const char* cSql = [sql UTF8String];
        sqlite3_stmt* statement;
        if (sqlite3_prepare_v2(db, cSql, -1, &statement, NULL) == SQLITE_OK) {
            NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
            [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
            NSString* strDate = [dateFormatter stringFromDate:model.date];
            const char* cDate = [strDate UTF8String];
            const char* cContent = [model.content UTF8String];
            //调用sqlite3_bind_text函数绑定sql语句的参数,第2个参数为序号,从1开始,第4个参数为字符串长度,第5个参数为函数指针
            sqlite3_bind_text(statement, 1, cDate, -1, NULL);
            sqlite3_bind_text(statement, 2, cContent, -1, NULL);
            //调用sqlite3_step函数执行sql语句,若返回值为SQLITE_DONE则表示执行成功
            if (sqlite3_step(statement) == SQLITE_DONE) {
                NSLog(@"插入数据成功");
                sqlite3_finalize(statement);
                sqlite3_close(db);
                return 1;
            }else{
                NSLog(@"插入数据失败");
            }
        }
        sqlite3_finalize(statement);
        sqlite3_close(db);
    }
    return 0;
}

使用SQLite是比较高效、便捷的数据持久化方式,但是这样直接调用sqlite3的函数来进行数据持久化,会涉及到许多的sql语句以及objective-C和C语言之间类型转换的问题。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值