ios之数据持久化
9.1 数据持久化概述
iOS中可以有四种持久化数据的方式: 属性列表、对象归档、SQLite3和Core Data
9.2 iOS应用程序目录结构
iOS应用程序运行在Mac os模拟器时候,有一下临时目录模拟器3.1.3为例子:
/Users/tony/Library/Application Support/iPhone Simulator/3.1.3/Applications
IOS应用程序采用沙盒原理设计,ios每个应用程序都有自己的3个目录(Document,Library,tmp),互相之间不能访问。
Documents存放应用程序的数据。
Library目录下面还有Preferences和Caches目录,Preferences目录存放应用程序的使用偏好,Caches目录与Documents很相 似可以存放应用程序的数据。
tmp目录供应用程序存储临时文件。
9.3 读写属性列表
读取Documents目录下文件
可以获得应用程序的Documents文件夹。
NSArray* myPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* myDocPath = [myPaths objectAtIndex:0];
获取文件的完整路径。
- (NSString*)filePath:(NSString*)fileName {
NSArray* myPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* myDocPath = [myPaths objectAtIndex:0];
NSString* filePath = [myDocPath stringByAppendingPathComponent:fileName];
return filePath;
}
获取tmp目录
获取应用程序的tmp目录要比获取Documents目录容易的多。使用函数NSTemporaryDirectory ()可以获得tmp目录路径。
NSString* tempPath = NSTemporaryDirectory();
获取文件的完整路径。
NSString* tempFile = [tempPath stringByAppendingPathComponent:@"properties.plist"];
属性列表文件实例 :PropertesList
PropertesListViewController.h
#import "Student.h" @interface ViewController : UIViewController @property (retain, nonatomic) IBOutlet UITextField *studentNo;
@property (retain, nonatomic) IBOutlet UITextField *studentName;
@property (retain, nonatomic) IBOutlet UITextField *studentClass;
- (IBAction)save:(id)sender;
- (IBAction)load:(id)sender;
- (IBAction)endEditing:(id)sender;
- (IBAction)saveToArchiver:(id)sender;
- (IBAction)loadFromArchiver:(id)sender;
- (NSString*)filePath:(NSString*)fileName;
@end
PropertesListViewController.m
@synthesize studentNo;
@synthesize studentName;
@synthesize studentClass; - (NSString*)filePath:(NSString*)fileName {
NSArray* myPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* myDocPath = [myPaths objectAtIndex:0];
NSString* filePath = [myDocPath stringByAppendingPathComponent:fileName];
return filePath;
} - (IBAction)save:(id)sender { NSString* fileName = [self filePath:@"properties.plist"];
NSLog(fileName);
NSMutableArray* data = [[NSMutableArray alloc]init]; [data addObject:studentNo.text];
[data addObject:studentName.text];
[data addObject:studentClass.text];
[data writeToFile:fileName atomically:YES];
} - (IBAction)load:(id)sender {
NSString* fileName = [self filePath:@"properties.plist"];
if ([[NSFileManager defaultManager]fileExistsAtPath:fileName]) {
NSArray* data = [[NSArray alloc]initWithContentsOfFile:fileName];
studentNo.text = [data objectAtIndex:0];
studentName.text = [data objectAtIndex:1];
studentClass.text = [data objectAtIndex:2];
[data release];
} } - (IBAction)endEditing:(id)sender {
[sender resignFirstResponder];
}
9.4 对象归档
对象归档实例:Encoding
对象归档
“归档”是值另一种形式的序列化,对模型对象进行归档的技术可以轻松将复杂的对象写入文件,然后再从中读取它们,只要在类中实现的每个属性都是基本数据类型(如int或float)或都是符合NSCoding协议的某个类的实例,你就可以对你的对象进行完整归档。
实现NSCoding协议
NSCoding协议声明了两个方法: -(void)encodeWithCoder:(NSCoder *)aCoder,是将对象写入到文件中。
-(id)initWithCoder:(NSCoder *)aDecoder,是将文件中数据读入到对象中。
实现NSCopying协议
NSCopying协议声明了一个方法: -(id)copyWithZone:(NSZone *)zone ,是将对象复制方法。
Student.h
@interface Student : NSObject<NSCoding, NSCopying> @property (retain, nonatomic) NSString* studentNo;
@property (retain, nonatomic) NSString* studentName;
@property (retain, nonatomic) NSString* studentClass; @end
Student.m
#import "Student.h" @implementation Student @synthesize studentNo = _studentNo;
@synthesize studentName = _studentName;
@synthesize studentClass = _studentClass; #pragma mark NSCopying - (id)copyWithZone:(NSZone *)zone {
Student* copy = [[[self class]allocWithZone:zone]init];
copy.studentNo = [_studentNo copyWithZone:zone];
copy.studentName = [_studentName copyWithZone:zone];
copy.studentClass = [_studentClass copyWithZone:zone];
return copy;
} #pragma mark NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:_studentNo forKey:@"studentNo"];
[aCoder encodeObject:_studentName forKey:@"studentName"];
[aCoder encodeObject:_studentClass forKey:@"studentClass"];
}
- (id)initWithCoder:(NSCoder *)aDecoder {
_studentNo = [aDecoder decodeObjectForKey:@"studentNo"];
_studentName = [aDecoder decodeObjectForKey:@"studentName"];
_studentClass = [aDecoder decodeObjectForKey:@"studentClass"];
return self;
}
-(NSString*)description {
return [[[NSString alloc]initWithFormat:@"no:%@ name:%@ class:%@", _studentNo, _studentName, _studentClass]autorelease];
} - (void)dealloc {
[_studentName release];
[_studentClass release];
[_studentNo release];
[super dealloc];
}
@end
EncodingViewController.h
详细见上。
EncodingViewController.m
- (IBAction)saveToArchiver:(id)sender {
NSString* fileName = [self filePath:@"student.archiver"];
NSMutableData* data = [NSMutableData data];
NSKeyedArchiver* archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:data];
Student* student = [[Student alloc]init];
student.studentNo = studentNo.text;
student.studentName = studentName.text;
student.studentClass = studentClass.text;
[archiver encodeObject:student forKey:@"myStudent"];
[archiver finishEncoding];
[data writeToFile:fileName atomically:YES];
[archiver release];
[student release];
}
NSMutableData * theData = [NSMutableData data];用于包含编码的数据。
NSKeyedArchiver * archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:theData];创建NSKeyedArchiver实例,用于将对象归档到此theData实例中。
[archiver encodeObject:student forKey:@"mystudent"]; 使用“键-值”对编码来对希望包含在归档中的对象进行归档。
[theData writeToFile:filename atomically:YES]; 写入数据到归档文件。
EncodingViewController.m
- (IBAction)loadFromArchiver:(id)sender {
NSString* fileName = [self filePath:@"student.archiver"];
NSData* data = [NSData dataWithContentsOfFile:fileName];
if ([data length] > 0) {
NSKeyedUnarchiver* unArchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:data];
Student* student = [unArchiver decodeObjectForKey:@"myStudent"];
studentNo.text = student.studentNo;
studentName.text = student.studentName;
studentClass.text = student.studentClass;
[unArchiver finishDecoding];
[unArchiver release];
}
}
NSData * theData =[NSData dataWithContentsOfFile:filename];从归档文件中获得NSData实例。
NSKeyedUnarchiver * archiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:theData];
创建一个NSKeyedUnarchiver实例对数据进行解码。Student *student = [archiver decodeObjectForKey:@"mystudent"];
使用与归档编码使用相同的键对象进行解码。
9.5 访问SQLite
SQLite数据库
SQLite是一个开源的嵌入式关系数据库,它在2000年由D. Richard Hipp发布,它的减少应用程序管理数据的开销,SQLite可移植性好,很容易使用,很小,高效而且可靠。
SQLite嵌入到使用它的应用程序中,它们共用相同的进程空间,而不是单独的一个进程。从外部看,它并不像一个RDBMS,但在进程内部,它却是完整的,自包含的数据库引擎。 嵌入式数据库的一大好处就是在你的程序内部不需要网络配置,也不需要管理。因为客户端和服务器在同一进程空间运行。SQLite 的数据库权限只依赖于文件系统,没有用户帐户的概念。SQLite 有数据库级锁定,没有网络服务器。它需要的内存,其它开销很小,适合用于嵌入式设备。你需要做的仅仅是把它正确的编译到你的程序。
SQLite数据类型
SQLite是无类型的,这意味着你可以保存任何类型的数据到你所想要保存的任何表的任何列中, 无
论这列声明的数据类型是什么,对于SQLite来说对字段不指定类型是完全有效的,如:
Create Table ex1(a, b, c);
SQLite允许忽略数据类型,但是仍然建议在你的Create Table语句中指定数据类型, 因为数据类型对于你和其他的程序员交流, 或者你准备换掉你的数据库引擎。 SQLite支持常见的数据类型, 如:
在iOS中使用SQLite3
为了能够在iOS中使用SQLite3需要是将libsqlite3.dylib类库添加到Xcode工程中,在工程的Frameworks(框架) 文件夹右键添加存在Frameworks
或者导航到 /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/ iPhoneSimulator<version>.sdk/usr/lib 目录下面找到libsqlite3.dylib.
实例:StudentSQLite3
StudentSQLite3ViewController.h
#import "sqlite3.h" #define DATA_FILE @"data.sqlite3"
#define TABLE_NAME @"student"
#define FIELDS_NAME_SID @"studentId"
#define FIELDS_NAME_SNAME @"studentName"
#define FIELDS_NAME_SCLASS @"studentClass" @interface ViewController : UIViewController {
sqlite3* db;
}
@property (retain, nonatomic) IBOutlet UITextField *studentId;
@property (retain, nonatomic) IBOutlet UITextField *studentName;
@property (retain, nonatomic) IBOutlet UITextField *studentClass;
- (IBAction)saveFromSqlite:(id)sender;
- (IBAction)loadFromSqlite:(id)sender; -(NSString*)dataFile;
-(IBAction)textFieldDoneEditing:(id)sender; @end
StudentSQLite3ViewController.m
@synthesize studentId;
@synthesize studentName;
@synthesize studentClass; -(NSString*)dataFile {
NSArray* myPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* myDocPath = [myPaths objectAtIndex:0];
NSString* fileName = [myDocPath stringByAppendingFormat:DATA_FILE];
return fileName;
}
无参数SQLite3处理过程
1、打开数据库sqlite3_open。
2、创建数据库表和执行SQL语句sqlite3_exec。
3、释放资源sqlite3_close。
创建数据库
- (void)viewDidLoad {
[super viewDidLoad];
NSString* fileName = [self dataFile];
NSLog(@"%@", fileName);
if (sqlite3_open([fileName UTF8String], &db) != SQLITE_OK) {
sqlite3_close(db);
NSAssert(NO, @"OPEN SQLITE DATABASE ERROR!");
} else {
char* error;
NSString* createSQL = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@(%@ TEXT PRIMARY KEY, %@ TEXT, %@% TEXT);",
TABLE_NAME, FIELDS_NAME_SID, FIELDS_NAME_SNAME, FIELDS_NAME_SCLASS];
if (sqlite3_exec(db, [createSQL UTF8String], NULL, NULL, &error)) {
sqlite3_close(db);
NSAssert1(NO, @"CREATE TABLE ERROR", error);
} else {
sqlite3_close(db);
}
}
}
sqlite3_open([[self dataFilePath] UTF8String], &db) != SQLITE_OK sqlite3_open打开数据库,注意:在sqlite3中的函数都是使用C字符串[self dataFilePath] UTF8String]是将NSString字符串转换为C字符串,&db是sqlite3指针(* db)的地址。
该函数sqlite3_open返回SQLITE_OK打开成功。
sqlite3_exec(db, [tablesql UTF8String], NULL, NULL, &err) != SQLITE_OK
sqlite3_exec是执行任何不带返回值sql语句,第2个参数是要执行的sql语句,第3个参数是要回调函数,第4个参数是要回调函数的参数,第5个参数是执行出错的字符串。
sqlite3_close(db); 是关闭数据库。
NSAssert是断言函数,当断言失败时候打印信息。
NSAssert1是带有一个参数的NSAssert函数,此外还有NSAssert2等函数。
有参数的SQLite3处理过程
1、打开数据库sqlite3_open。
2、预处理SQL语句sqlite3_prepare_v2。
3、绑定参数sqlite3_bind_text。
4、执行语句sqlite3_step(statement) 。
5、释放资源sqlite3_finalizesqlite3_close。
数据保存
- (IBAction)saveFromSqlite:(id)sender {
NSString* fileName = [self dataFile];
NSLog(@"%@", fileName);
if (sqlite3_open([fileName UTF8String], &db)) {
sqlite3_close(db);
NSAssert(NO, @"OPEN DATABASE ERROR");
} else {
NSString* sqlStr = [NSString stringWithFormat:@"INSERT OR REPLACE INTO %@(%@, %@, %@) VALUES(?, ?, ?)",TABLE_NAME, FIELDS_NAME_SID, FIELDS_NAME_SNAME, FIELDS_NAME_SCLASS];
sqlite3_stmt* statement;
//预处理过程
if (sqlite3_prepare(db, [sqlStr UTF8String], -1, &statement, NULL) == SQLITE_OK) {
//绑定参数开始
sqlite3_bind_text(statement, 1, [studentId.text UTF8String], -1, NULL);
sqlite3_bind_text(statement, 2, [studentName.text UTF8String], -1, NULL);
sqlite3_bind_text(statement, 3, [studentClass.text UTF8String], -1, NULL);
//执行插入
if (sqlite3_step(statement) != SQLITE_DONE) {
NSAssert(0, @"INSERT DATABASE ERROR!");
}
}
sqlite3_finalize(statement);
sqlite3_close(db);
}
}
sqlite3_prepare_v2(db, [sqlStr UTF8String], -1, &statement, nil) == SQLITE_OK
sqlite3_prepare_v2执行sql语句,第3个参数-1代表全部sql字符串长度,第4个参数&statement是sqlite3_stmt指针(* statement)的地址,第5个参数是sql语句没有被执行的部分语句。
sqlite3_bind_text(statement, 1, [studentId.text UTF8String], -1, NULL);
是绑定参数,第2个参数为序号(从1开始),第3个参数为字符串值,第4个参数为字符串长度。 第5个参数为一个函数指针,SQLITE3执行完操作后回调此函数,通常用于释放字符串占用的内存。
sqlite3_step(statement) != SQLITE_DONE判断是否执行完成sql语句执行。
sqlite3_finalize(statement)和sqlite3_close(db)释放资源。
查询数据
- (IBAction)loadFromSqlite:(id)sender {
NSString* fileName = [self dataFile];
NSLog(@"%@", fileName);
if (sqlite3_open([fileName UTF8String], &db) != SQLITE_OK) {
sqlite3_close(db);
NSAssert(NO, @"OPEN DATABASE ERROR!");
} else {
NSString* sqlStr = [NSString stringWithFormat:@"SELECT %@,%@,%@ FROM %@ WHERE %@=?",
FIELDS_NAME_SID, FIELDS_NAME_SNAME, FIELDS_NAME_SCLASS, TABLE_NAME, FIELDS_NAME_SID];
sqlite3_stmt* statement;
//预处理过程
if (sqlite3_prepare_v2(db, [sqlStr UTF8String], -1, &statement, NULL) == SQLITE_OK) {
//绑定参数开始
sqlite3_bind_text(statement, 1, "1000", -1, NULL);
//执行
while (sqlite3_step(statement) == SQLITE_ROW) {
char* field1 = (char*)sqlite3_column_text(statement, 0);
NSString* field1Str = [[NSString alloc]initWithUTF8String:field1];
studentId.text = field1Str; char* field2 = (char*)sqlite3_column_text(statement, 1);
NSString* field2Str = [[NSString alloc]initWithUTF8String:field2];
studentName.text = field2Str; char* field3 = (char*)sqlite3_column_text(statement, 2);
NSString* field3Str = [[NSString alloc]initWithUTF8String:field3];
studentClass.text = field3Str; [field1Str release];
[field2Str release];
[field3Str release];
}
}
sqlite3_finalize(statement);
sqlite3_close(db);
}
}
while (sqlite3_step(statement) == SQLITE_ROW) sqlite3_step(statement) == SQLITE_ROW单步执行并判断sql语句执行的状态。
char *field1 = (char *) sqlite3_column_text(statement, 0); sqlite3_column_text(statement, 0);取出字段值,第2个参数是列的顺序,序号是从0开始。
NSString *field1Str = [[NSString alloc] initWithUTF8String: field1];构建NSSting字符串。
其它部分代码
-(IBAction)textFieldDoneEditing:(id)sender {
[sender resignFirstResponder];
}
- (void)viewDidUnload
{
[self setStudentId:nil];
[self setStudentName:nil];
[self setStudentClass:nil];
[super viewDidUnload];
} - (void)dealloc {
[studentId release];
[studentName release];
[studentClass release];
[super dealloc];
}
ios之数据持久化的更多相关文章
- iOS之数据持久化方案
概论 所谓的持久化,就是将数据保存到硬盘中,使得在应用程序或机器重启后可以继续访问之前保存的数据.在iOS开发中,有很多数据持久化的方案,接下来我将尝试着介绍一下5种方案: plist文件(属性列表) ...
- iOS的数据持久化
所谓的持久化,就是将数据保存到硬盘中,使得在应用程序或机器重启后可以继续访问之前保存的数据.在iOS开发中,有很多数据持久化的方案,接下来我将尝试着介绍一下5种方案: plist文件(属性列表) pr ...
- IOS - 本地数据持久化
转:相对复杂的App仅靠内存的数据肯定无法满足,数据写磁盘作持久化存储是几乎每个客户端软件都需要做的.简单如“是否第一次打开”的BOOL值,大 到游戏的进度和状态等数据,都需要进行本地持久化存储.这些 ...
- iOS - OC 数据持久化
1.Sandbox 沙箱 iOS 为每个应用提供了独立的文件空间,一个应用只能直接访问为本应用分配的文件目录,不可以访问其他目录,每个应用自己独立的访问空间被称为该应用的沙盒.也就是说,一个应用与文件 ...
- iOS - Swift 数据持久化
1.Sandbox 沙箱 iOS 为每个应用提供了独立的文件空间,一个应用只能直接访问为本应用分配的文件目录,不可以访问其他目录,每个应用自己独立的访问空间被称为该应用的沙盒.也就是说,一个应用与文件 ...
- IOS开发--数据持久化篇之文件存储(一)
前言:个人觉得开发人员最大的悲哀莫过于懂得使用却不明白其中的原理.在代码之前我觉得还是有必要简单阐述下相关的一些知识点. 因为文章或深或浅总有适合的人群.若有朋友发现了其中不正确的观点还望多多指出,不 ...
- QF——iOS中数据持久化的几种方式
数据持久化的几种方式: 一.属性列表文件: .plist文件是种XML文件.数组,字典都可以和它互相转换.数组和字典可以写入本地变成plist文件.也可以读取本地plist文件,生成数组或字典. 读取 ...
- iOS中 数据持久化 UI高级_17
数据持久化的本质就是把数据由内写到本地(硬盘中),在iOS指将数据写到沙盒文件夹下: 沙盒机制:指的就是采用沙盒文件夹的形式管理应用程序的本地文件,而且沙盒文件夹的名字是随机分配的,采用十六进制方法命 ...
- iOS开发——数据持久化Swift篇&使用Core Data进行数据持久化存储
使用Core Data进行数据持久化存储 一,Core Data介绍 1,Core Data是iOS5之后才出现的一个数据持久化存储框架,它提供了对象-关系映射(ORM)的功能,即能够将对象转化成 ...
随机推荐
- 张高兴的 .NET Core IoT 入门指南:(三)使用 I2C 进行通信
什么是 I2C 总线 I2C 总线(Inter-Integrated Circuit Bus)是设备与设备间通信方式的一种.它是一种串行通信总线,由飞利浦公司在1980年代为了让主板.嵌入式系统或手机 ...
- SCUT - 244 - 全新的游戏 - 凸包
https://scut.online/p/244 除了常规的求凸包求面积,还有一个判断点在凸包内,先找出点所在的三角扇区. #include<bits/stdc++.h> using n ...
- hdoj1024【DP.最 大 m 字 段 和】(写完我都怕。。。不忍直视。。)
弱弱上路,看了好多题解....[A的] 题意就是求最大m子段和. 我们先用a[1e6+7]存入数据: 定义:DP[ i , j ] 为前 j 个元素的 i 个子段的最大和,且第 i 个子段中包含了元素 ...
- JSP | 基础 | 加载类失败:com.mysql.jdbc.Driver
两个原因: 1. 连接数据库需要的jar包没有导入Tomcat的lib库中 解决方案: 打开Tomcat的安装目录下的lib文件夹,把jar包拖进lib库后,重启tomcat服务器 2. mysql ...
- Magento 缓存机制简析
在知道缓存机制前,首先需要知道,Magento的路由机制,这边就不做赘述了,百度一大堆. 下面一个简单的缓存生效流程: A:首先在页面开始时,Magento在app\code\core\Mage\Co ...
- 对protected修饰符的范围用代码说明(同时说明用protected修饰的属性,在继承时,一定程度上破坏了封装)
目录结构: 本类: 本包: 子孙类: 其他包:
- js调用本地程序
前几天,做项目时候用到js调用本地的程序,找了好多资料,一种是写入注册表,一种是写一个浏览器插件,相对来说,写一个注册表更简单一点,因为需求很紧.下面就是我的总结,希望可以对你们有所帮助,具体从哪里找 ...
- Android设计模式——MVP
一.什么是MVP MVP:全称 Model-View-Presenter. MVP框架由3部分组成:View层负责显示,Presenter层负责逻辑处理,Model层提供数据. View:负责绘制UI ...
- AJPFX关于Set接口学习笔记及总结
Set接口中的方法和Collection中方法一致的.Set接口取出方式只有一种,迭代器. |--HashSet:底层数据结构是哈希表,线程是不同步的.无序,高效: HashSet集合保证元素唯一性: ...
- Ant题解
Description: 一根长度为L厘米的木棒上有N只蚂蚁,每只蚂蚁要么向左走,要么向右走,速度为1厘米/秒.当两只蚂蚁相撞时,他们会同时掉头(掉头时间不计)给出每只蚂蚁距离木棒左端的距离,问多少秒 ...