1.plist文件存储
每个iOS应用都有自己的应用沙盒(应用沙盒就是文件系统目录),与其他文件系统隔离。应用必须待在自己的沙盒里,其他应用不能访问该沙盒
应用沙盒的文件系统目录,如下图所示(假设应用的名称叫Layer)
模拟器应用沙盒的根路径在: (apple是用户名, 6.0是模拟器版本)
/Users/apple/Library/Application Support/iPhone Simulator/6.0/Applications
Document 保存应用运行时生成的需要持久化的数据,iTunes同步设备时会备份该目录。例如,游戏应用可将游戏存档保存在该目录
temp 保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时不会备份该目录
Library/Caches 保存应用运行时生成的需要持久化的数据,iTunes同步设备时不会备份该目录。一般存储体积大、不需要备份的非重要数据
Library/Preference: 保存应用的所有偏好设置,iOS的Settings(设置)应用会在该目录中查找应用的设置信息。iTunes同步设备时会备份该目录
下面是示例代码:
1 /** 保存数据*/ 2 - (IBAction)saveBtn 3 { 4 NSLog(@"保存"); 5 //1.获取沙盒根路径 6 NSString *homePath = NSHomeDirectory(); 7 //2.document路径 8 NSString *path = [homePath stringByAppendingPathComponent:@"Documents"]; 9 //3.新建数据 10 NSArray *array = [NSArray arrayWithObjects:@"nan",@(22), nil]; 11 NSDictionary *dict = @{@"sss":@"sddd",@"ssssaw":@(1222)}; 12 13 14 //4.存储数据 15 NSString *fullPath1 = [path stringByAppendingPathComponent:@"data1.plist"]; 16 NSString *fullPath2 = [path stringByAppendingPathComponent:@"data2.plist"]; 17 18 [array writeToFile:fullPath1 atomically:YES]; //数组写入plist 19 [dict writeToFile:fullPath2 atomically:YES]; 20 21 NSLog(@"dict - %@",dict); 22 } 23 24 /** 读取数据*/ 25 - (IBAction)readBtn 26 { 27 //1.获取home目录 28 NSString *home = NSHomeDirectory(); 29 //2.拼接Document目录 30 NSString *path = [home stringByAppendingPathComponent:@"Documents"]; 31 //3.文件路径 32 NSString *filePath1 = [path stringByAppendingPathComponent:@"data1.plist"]; 33 NSString *filePath2 = [path stringByAppendingPathComponent:@"data2.plist"]; 34 //读取文件 35 NSArray *array = [NSArray arrayWithContentsOfFile:filePath1]; 36 NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:filePath2]; 37 NSLog(@"array - %@, dict - %@",array , dict); 38 }
缺点:只能存储含有 writeToFile:方法的对象,如NSDictionary,NSArray等.
2.偏好设置 -- 存放目录 Library/Preference:
下面是示例代码
/** 保存数据*/ - (IBAction)save { // 1.利用NSUserDefaults,就能直接访问软件的偏好设置(Library/Preferences)是个单例对象 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; //2.存储数据 [defaults setObject:@"sd" forKey:@"user"];//其中要保存的数据是setObject:@"sd",@“sd”是数据,forKey:@"user"是以user的键值保存的,
/**
key - value
@"user" - @"sd"
*/
[defaults setObject:@"123w" forKey:@"test"]; [defaults setInteger:20 forKey:@"age"]; [defaults setBool:YES forKey:@"auto_login"]; //3.立刻同步(相当于更新数据) [defaults synchronize]; } /** 读取数据*/ - (IBAction)read { //1.建立NSUserDefaults对象 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; //2.读取数据 NSString *user = [defaults objectForKey:@"user"]; NSString *test = [defaults objectForKey:@"test"]; NSInteger age = [defaults integerForKey:@"age"]; BOOL autoLogin = [defaults boolForKey:@"auto_login"]; NSLog(@"user - %@ test - %@ age - %d autoLogin - %d ,",user,test,age,autoLogin); }
//下面是解档归档基本OC对象
- (void)test
{
NSString *mName = @"zhangsan";
// 获取doc的目录
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
// 拼接保存的路径
NSString *filePath = [docPath stringByAppendingPathComponent:@"dataList"];
// NSData *mData = [mName dataUsingEncoding:NSUTF8StringEncoding];
[NSKeyedArchiver archiveRootObject:mName toFile:filePath];
NSString *testName = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
NSLog(@"解档出来的数据是 ----- %@",testName);
}
缺点:本质还是plist文件存储,相对于plist文件存储来讲存储数据更快捷.
3.NSKeyedArchiver(NSCoding)
每次归档对象时,都会调用这个方法。一般在这个方法里面指定如何归档对象中的每个实例变量,可以使用encodeObject:forKey:方法归档实例变量
每次从文件中恢复(解码)对象时,都会调用这个方法。一般在这个方法里面指定如何解码文件中的数据为对象的实例变量,可以使用decodeObject:forKey方法解码实例变量
示例代码
1 #import <Foundation/Foundation.h> 2 3 @interface Person : NSObject <NSCoding> 4 5 @property (nonatomic , copy) NSString *name; 6 @property (nonatomic , assign) int age; 7 @property (nonatomic , assign) double height; 8 9 @end 10 11 12 #import "Person.h" 13 14 @implementation Person 15 16 //归档的时候调用 17 /** 将某个对象写入文件的时候会调用,在这个方法中说明哪些对象的哪些属性需要存储*/ 18 - (void)encodeWithCoder:(NSCoder *)enCoder 19 { 20 NSLog(@"enCoder - %@",enCoder); 21 [enCoder encodeObject:self.name forKey:@"name"]; 22 [enCoder encodeInt:self.age forKey:@"age"]; 23 [enCoder encodeDouble:self.height forKey:@"height"]; 24 25 } 26 27 /** 解档时候调用,在这个方法中说清楚哪些属性要解档*/ 28 - (id)initWithCoder:(NSCoder *)decoder 29 { 30 if (self = [super init]) 31 { 32 //读取文件内容 33 self.name = [decoder decodeObjectForKey:@"name"]; 34 self.age = [decoder decodeIntForKey:@"age"]; 35 self.height = [decoder decodeDoubleForKey:@"height"]; 36 37 } 38 39 return self; 40 } 41 42 43 @end 44 45 46 #import "SDViewController.h" 47 #import "Person.h" 48 49 @interface SDViewController () 50 51 @end 52 53 @implementation SDViewController 54 55 - (void)viewDidLoad 56 { 57 [super viewDidLoad]; 58 59 60 } 61 62 - (IBAction)save 63 { 64 //1.数据对象 65 Person *p1 = [[Person alloc] init]; 66 p1.name = @"王麻子"; 67 p1.age = 20; 68 p1.height = 1.98; 69 Person *p2 = [[Person alloc] init]; 70 p2.name = @"李四"; 71 p2.age = 56; 72 p2.height = 1.68; 73 //2.归档数据对象 74 //2.1获得文件的Documents全路径 75 NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject]; 76 //2.2获得文件的全路径 77 NSString *path = [doc stringByAppendingPathComponent:@"person.txt"]; 78 //2.3将对象归档 79 [NSKeyedArchiver archiveRootObject:p1 toFile:path]; 80 81 } 82 - (IBAction)read 83 { 84 // 1.获得Documents的全路径 85 NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; 86 // 2.获得文件的全路径 87 NSString *path = [doc stringByAppendingPathComponent:@"person.txt"]; 88 // 3.从文件中读取Person对象 89 Person *p3 = [NSKeyedUnarchiver unarchiveObjectWithFile:path]; 90 91 NSLog(@"%@ %d %f", p3.name, p3.age, p3.height); 92 93 } 94 95 96 @end
NSKeyedArchiver-归档对象的注意:
1 Person.h里面 2 3 #import <Foundation/Foundation.h> 4 5 @interface Person : NSObject <NSCoding> 6 7 @property (nonatomic , copy) NSString *name; 8 @property (nonatomic , assign) int age; 9 @property (nonatomic , assign) double height; 10 11 @end 12 13 Person.m里面 14 #import "Person.h" 15 16 @implementation Person 17 18 //归档的时候调用 19 /** 将某个对象写入文件的时候会调用,在这个方法中说明哪些对象的哪些属性需要存储*/ 20 - (void)encodeWithCoder:(NSCoder *)enCoder 21 { 22 NSLog(@"enCoder - %@",enCoder); 23 [enCoder encodeObject:self.name forKey:@"name"]; 24 [enCoder encodeInt:self.age forKey:@"age"]; 25 [enCoder encodeDouble:self.height forKey:@"height"]; 26 27 } 28 29 /** 解档时候调用,在这个方法中说清楚哪些属性要解档*/ 30 - (id)initWithCoder:(NSCoder *)decoder 31 { 32 if (self = [super init]) 33 { 34 //读取文件内容 35 self.name = [decoder decodeObjectForKey:@"name"]; 36 self.age = [decoder decodeIntForKey:@"age"]; 37 self.height = [decoder decodeDoubleForKey:@"height"]; 38 39 } 40 41 return self; 42 } 43 44 45 @end 46 47 SDViewController.m里面 48 49 #import "SDViewController.h" 50 #import "Person.h" 51 52 @interface SDViewController () 53 54 @end 55 56 @implementation SDViewController 57 58 - (void)viewDidLoad 59 { 60 [super viewDidLoad]; 61 // Do any additional setup after loading the view, typically from a nib. 62 63 } 64 65 - (void)didReceiveMemoryWarning 66 { 67 [super didReceiveMemoryWarning]; 68 // Dispose of any resources that can be recreated. 69 } 70 71 72 - (IBAction)save 73 { 74 //1.数据对象 75 Person *p1 = [[Person alloc] init]; 76 p1.name = @"王麻子"; 77 p1.age = 20; 78 p1.height = 1.98; 79 Person *p2 = [[Person alloc] init]; 80 p2.name = @"李四"; 81 p2.age = 56; 82 p2.height = 1.68; 83 //2.归档数据对象 84 //2.1获得文件的Documents全路径 85 NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject]; 86 //2.2获得文件的全路径 87 NSString *path = [doc stringByAppendingPathComponent:@"person.txt"]; 88 // //2.3将对象归档 89 // [NSKeyedArchiver archiveRootObject:p1 toFile:path]; 90 // 91 // 新建一块可变数据区 92 NSMutableData *data = [NSMutableData data]; 93 // 将数据区连接到一个NSKeyedArchiver对象 94 NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; 95 [archiver encodeObject:p1 forKey:@"person1"]; 96 [archiver encodeObject:p2 forKey:@"person2"]; 97 // 存档完毕(一定要调用这个方法) 98 [archiver finishEncoding]; 99 //将存档的数据写入文件 100 [data writeToFile:path atomically:YES]; 101 102 } 103 - (IBAction)read 104 { 105 // 1.获得Documents的全路径 106 NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; 107 // 2.获得文件的全路径 108 NSString *path = [doc stringByAppendingPathComponent:@"person.txt"]; 109 // 3.从文件中读取Student对象 110 // Person *p3 = [NSKeyedUnarchiver unarchiveObjectWithFile:path]; 111 NSData *data = [NSData dataWithContentsOfFile:path]; 112 113 // 根据数据,解析成一个NSKeyedUnarchiver对象 114 NSKeyedUnarchiver *unchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; 115 Person *p1 = [unchiver decodeObjectForKey:@"person1"]; 116 Person *p2 = [unchiver decodeObjectForKey:@"person2"]; 117 [unchiver finishDecoding]; 118 NSLog(@"%@ %d %f", p1.name, p1.age, p1.height); 119 NSLog(@"%@ %d %f", p2.name, p2.age, p2.height); 120 121 } 122 123 124 125 @end
NSCoder.h
- (void)encodeValueOfObjCType:(const char *)type at:(const void *)addr; //解档C类型数据,addr传入地址
- (void)encodeDataObject:(NSData *)data; //归档一个NSData型对象
- (void)decodeValueOfObjCType:(const char *)type at:(void *)data; ////解档C类型数据
- (NSData *)decodeDataObject;//解档一个NSData型对象
@end
@interface NSCoder (NSExtendedCoder)
/** 归档相关函数*/
- (void)encodeObject:(id)object;
- (void)encodeRootObject:(id)rootObject;
- (void)encodeBycopyObject:(id)anObject;
- (void)encodeByrefObject:(id)anObject;
- (void)encodeConditionalObject:(id)object;
- (void)encodeValuesOfObjCTypes:(const char *)types, ...;
- (void)encodeArrayOfObjCType:(const char *)type count:(NSUInteger)count at:(const void *)array;
- (void)encodeBytes:(const void *)byteaddr length:(NSUInteger)length;
/** 解档相关函数*/
- (id)decodeObject;
- (void)decodeValuesOfObjCTypes:(const char *)types, ...;
- (void)decodeArrayOfObjCType:(const char *)itemType count:(NSUInteger)count at:(void *)array;
- (void *)decodeBytesWithReturnedLength:(NSUInteger *)lengthp NS_RETURNS_INNER_POINTER;
- (unsigned)systemVersion;
//是否遵循KeyedCoding
- (BOOL)allowsKeyedCoding;
/** 归档相关函数*/
- (void)encodeObject:(id)objv forKey:(NSString *)key;
- (void)encodeConditionalObject:(id)objv forKey:(NSString *)key;
- (void)encodeBool:(BOOL)boolv forKey:(NSString *)key;
- (void)encodeInt:(int)intv forKey:(NSString *)key;
- (void)encodeInt32:(int32_t)intv forKey:(NSString *)key;
- (void)encodeInt64:(int64_t)intv forKey:(NSString *)key;
- (void)encodeFloat:(float)realv forKey:(NSString *)key;
- (void)encodeDouble:(double)realv forKey:(NSString *)key;
- (void)encodeBytes:(const uint8_t *)bytesp length:(NSUInteger)lenv forKey:(NSString *)key;
/** 解档相关函数*/
- (BOOL)containsValueForKey:(NSString *)key;
- (id)decodeObjectForKey:(NSString *)key;
- (BOOL)decodeBoolForKey:(NSString *)key;
- (int)decodeIntForKey:(NSString *)key;
- (int32_t)decodeInt32ForKey:(NSString *)key;
- (int64_t)decodeInt64ForKey:(NSString *)key;
- (float)decodeFloatForKey:(NSString *)key;
- (double)decodeDoubleForKey:(NSString *)key;
- (const uint8_t *)decodeBytesForKey:(NSString *)key returnedLength:(NSUInteger *)lengthp NS_RETURNS_INNER_POINTER; // returned bytes immutable!
- (void)encodeInteger:(NSInteger)intv forKey:(NSString *)key NS_AVAILABLE(10_5, 2_0);
- (NSInteger)decodeIntegerForKey:(NSString *)key NS_AVAILABLE(10_5, 2_0);
// Returns YES if this coder requires secure coding. Secure coders check a list of allowed classes before decoding objects, and all objects must implement NSSecureCoding.
//是否安全解档
- (BOOL)requiresSecureCoding NS_AVAILABLE(10_8, 6_0);
SQLite3 SQLite3是一款开源的嵌入式关系型数据库,可移植性好、易使用、内存开销小.SQLite3是无类型的,意味着你可以保存任何类型的数据到任意表的任意字段中。 数据库语句 /*简单约束*/ //如果表不存在就创建一张t_student的表(id为主键,自动增长,name text类型,age integer类型); CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER); //如果表不存在就创建一张t_student的表(id为主键,自动增长,name text类型不能为空,age integer类型不能为空); CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, age INTEGER NOT NULL); //如果表不存在就创建一张t_student的表(id为主键,自动增长,name text类型,并且每一个是唯一的,age integer类型不能为空); CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE, age INTEGER); //如果表不存在就创建一张t_student的表(id为主键,自动增长,name text类型,age integer类型默认为1); CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER DEFAULT 1); /*分页*/ //先将表按照升序排,跳过最前面30条语句,然后取10条记录 SELECT * FROM t_student ORDER BY id ASC LIMIT 30, 10; /*排序*/ //取出表中score > 50的数据并按照降序排列 SELECT * FROM t_student WHERE score > 50 ORDER BY age DESC; //取出表中score<50的数据并按照升序排列,score>50的数据按照降序排列 SELECT * FROM t_student WHERE score < 50 ORDER BY age ASC , score DESC; /*计量*/ //统计表中age > 50的个数 SELECT COUNT(*) FROM t_student WHERE age > 50; /*别名*/ //将name 命名为 myName, age 命名为 myAge, score 命名为myScore SELECT name as myName, age as myAge, score as myScore FROM t_student; //将name 命名为 myName, age 命名为 myAge, score 命名为myScore SELECT name myName, age myAge, score myScore FROM t_student; //给t_student表起个别名叫做s,利用s来引用表中的字段,取出age > 50 的数据,将name 命名为 myName, age 命名为 myAge, score 命名为myScore SELECT s.name myName, s.age myAge, s.score myScore FROM t_student s WHERE s.age > 50; /*查询*/ //从表中查询name,age,score SELECT name, age, score FROM t_student; //查询整张表 SELECT * FROM t_student; /*修改指定数据*/ //从表中取出age = 10 的那条数据,将name 字段值设为MM UPDATE t_student SET name = 'MM' WHERE age = 10; /从表中取出age = 7 的那条数据,将name 字段值设为WW UPDATE t_student SET name = 'WW' WHERE age is 7; //取出表中age < 20 的数据,并将name 全部设置为XXOO UPDATE t_student SET name = 'XXOO' WHERE age < 20; //取出表中age < 50 并且 score > 10的数据,将满足条件的每一条数据中的name字段设置为NNMM UPDATE t_student SET name = 'NNMM' WHERE age < 50 and score > 10; /*删除数据*/ //删除表中的数据 DELETE FROM t_student; /*更新数据*/ //将表中的name字段全部设置为MM UPDATE t_student SET name = 'MM'; /*插入数据*/ //往表中插入一条数据(name = jonathan , age = 28, score = 100) INSERT INTO t_student(age, score, name) VALUES ('28', 100, 'jonathan'); //往表中插入一条数据(name = lee , age = 28) INSERT INTO t_student(name, age) VALUES ('lee', '28'); //往表中插入一条数据(score = 100) INSERT INTO t_student(score) VALUES (100); /*添加主键*/ //如果表不存在就创建一张表,id为主键自动增长,integer类型,name 为text类型,age 为integer类型,score为浮点类型 CREATE TABLE IF NOT EXISTS t_student (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, score REAL); /*删除表*/ //销毁t_student表 DROP TABLE t_student; //如果表存在就销毁这张表 DROP TABLE IF EXISTS t_student; /****************************************************** 应 用 *****************************************************************/ - (void)viewDidLoad { [super viewDidLoad]; // 1.打开创建一个数据库 NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *fileName = [path stringByAppendingPathComponent:@"t_student.sqlite"]; int result = sqlite3_open(fileName.UTF8String, &_db); if (result == SQLITE_OK) { // 创建表 const char *sql = "CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , name TEXT NOT NULL, age INTERGER NOT NULL);"; char *error = nil; sqlite3_exec(self.db, sql, NULL, NULL, &error); if (error) { NSLog(@"创建失败"); }else{ NSLog(@"创建成功"); } }else{ NSLog(@"失败"); } } /** * 增加 */ - (IBAction)insertBtnClick:(id)sender { for (int i = 0; i < 100; i++) { NSString *name = [NSString stringWithFormat:@"lee-%d", i]; int age = arc4random_uniform(50) + 50; NSString *sql = [NSString stringWithFormat:@"INSERT INTO t_student(name, age) VALUES ('%@', %d);", name, age]; char *error = nil; sqlite3_exec(self.db, sql.UTF8String, NULL, NULL, &error); if (error) { NSLog(@"创建失败"); }else{ NSLog(@"创建成功"); } } } /** * 更新 */ - (IBAction)updateBtnClick:(id)sender { const char *sql = "UPDATE t_student SET name = 'DG';"; char *error = nil; sqlite3_exec(self.db, sql, NULL, NULL, &error); if (error) { NSLog(@"更新失败"); }else{ NSLog(@"更新成功"); } } /** * 删除 */ - (IBAction)deleteBtnClick:(id)sender { const char *sql = "DELETE FROM t_student;"; char *error = nil; sqlite3_exec(self.db, sql, NULL, NULL, &error); if (error) { NSLog(@"删除失败"); }else{ NSLog(@"删除成功"); } } /** * 查询 */ - (IBAction)selectBtnClick:(id)sender { const char *zSql = "SELECT * FROM t_student"; sqlite3_stmt *stmt; // 查询前的准备, 检查sql语句是否正确 int result = sqlite3_prepare_v2(self.db, zSql, -1, &stmt, NULL); if(result == SQLITE_OK) { // 准备完成,没有错误 // 提取查询到得数据到stmt, 一次提取一条 while(sqlite3_step(stmt) == SQLITE_ROW){ // 取出提取到得记录(数据)中的第0列数据和第一列数据 const unsigned char *name = sqlite3_column_text(stmt, 0); int age = sqlite3_column_int(stmt, 1); NSLog(@"%s, %d", name, age); } } } SqLite3小结 1.打开数据库 int sqlite3_open( const char *filename, // 数据库的文件路径 sqlite3 **.ppDb // 数据库实例 ); 2.执行任何SQL语句 int sqlite3_exec( sqlite3*, // 一个打开的数据库实例 const char *sql, // 需要执行的SQL语句 int (*callback)(void*,int,char**,char**), // SQL语句执行完毕后的回调 void *, // 回调函数的第1个参数 char **errmsg // 错误信息 ); 3.检查SQL语句的合法性(查询前的准备) int sqlite3_prepare_v2( sqlite3 *db, // 数据库实例 const char *zSql, // 需要检查的SQL语句 int nByte, // SQL语句的最大字节长度 sqlite3_stmt **ppStmt, // sqlite3_stmt实例,用来获得数据库数据 const char **pzTail ); 4.查询一行数据 int sqlite3_step(sqlite3_stmt*); // 如果查询到一行数据,就会返回SQLITE_ROW 5.利用stmt获得某一字段的值(字段的下标从0开始) double sqlite3_column_double(sqlite3_stmt*, int iCol); // 浮点数据 int sqlite3_column_int(sqlite3_stmt*, int iCol); // 整型数据 sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); // 长整型数据 const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); // 二进制文本数据 const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); // 字符串数据 6.SqLite3第三方框架FMDB使用小结 FMDB是iOS平台的SQLite数据库框架,FMDB以OC的方式封装了SQLite的C语言API. FMDB的优点 @1使用起来更加面向对象,省去了很多麻烦、冗余的C语言代码 @2对比苹果自带的Core Data框架,更加轻量级和灵活 @3提供了多线程安全的数据库操作方法,有效地防止数据混乱
FMDB简单使用示例代码
#import "CZViewController.h" #import "FMDB.h" @interface CZViewController () - (IBAction)insertBtnClick; - (IBAction)updateBtnClick; - (IBAction)deleteBtnClick; - (IBAction)queryBtnClick; @property (nonatomic, strong) FMDatabase *db; @end @implementation CZViewController - (void)viewDidLoad { [super viewDidLoad]; // 0.获取沙盒路径 NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject]; NSString *fileName = [path stringByAppendingPathComponent:@"t_student.sqlite"]; // 1.获得数据库对象 self.db = [FMDatabase databaseWithPath:fileName]; // 2.打开数据库 if ([self.db open]) { NSLog(@"打开成功"); // 2.1创建表 BOOL success = [self.db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_student (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT NOT NULL, age INTEGER NOT NULL);"]; if (success) { NSLog(@"创建表成功"); }else { NSLog(@"创建表失败"); } }else { NSLog(@"打开失败"); } } - (IBAction)insertBtnClick { for (int i = 0; i < 100; i++) { NSString *name = [NSString stringWithFormat:@"Jonathan-%d", i]; int age = arc4random_uniform(1000); BOOL success = [self.db executeUpdate:@"INSERT INTO t_student(name , age) VALUES(?, ?);", name, @(age)];// 注意只能拼接对象类型 if (success) { NSLog(@"添加成功"); }else { NSLog(@"添加失败"); } } } - (IBAction)updateBtnClick { BOOL success = [self.db executeUpdate:@"UPDATE t_student SET name = 'JACK' WHERE age < 50"]; if (success) { NSLog(@"修改成功"); }else { NSLog(@"修改失败"); } } - (IBAction)deleteBtnClick { BOOL success = [self.db executeUpdate:@"DELETE FROM t_student WHERE age < ?;", @50]; if (success) { NSLog(@"删除成功"); }else { NSLog(@"删除失败"); } } - (IBAction)queryBtnClick { // 1.查询 // FMResultSet *set = [self.db executeQuery:@"SELECT id, name, age FROM t_student;"]; FMResultSet *set = [self.db executeQuery:@"SELECT * FROM t_student;"]; // 2.取出数据 while ([set next]) { // 取出姓名 // NSString *name = [set stringForColumnIndex:1]; // 取出年龄 // int age = [set intForColumnIndex:2]; NSString *name = [set stringForColumn:@"name"]; int age = [set intForColumn:@"age"]; NSLog(@"name = %@, age = %d", name, age); } } @end
FMDB线程安全
#import "CZViewController.h" #import "FMDB.h" @interface CZViewController () - (IBAction)insertBtnClick; - (IBAction)updateBtnClick; - (IBAction)deleteBtnClick; - (IBAction)queryBtnClick; @property (nonatomic, strong) FMDatabase *db; @property (nonatomic, strong) FMDatabaseQueue *queue; @end @implementation CZViewController - (void)viewDidLoad { [super viewDidLoad]; // 0.获取沙盒路径 NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject]; NSString *fileName = [path stringByAppendingPathComponent:@"t_student.sqlite"]; // 1.获得数据库对象 // self.db = [FMDatabase databaseWithPath:fileName]; // 1.活的数据库队列对象 self.queue = [FMDatabaseQueue databaseQueueWithPath:fileName]; // 2.在数据库队列中执行线程安全的操作 [self.queue inDatabase:^(FMDatabase *db) { if ([db open]) { // 2.1创建表 BOOL success = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_person (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT NOT NULL, money INTEGER NOT NULL);"]; if (success) { NSLog(@"创建表成功"); }else { NSLog(@"创建表失败"); } } }]; } - (IBAction)insertBtnClick { [self.queue inDatabase:^(FMDatabase *db) { [db executeUpdate:@"INSERT INTO t_person(name, money) VALUES('Zs', 1000)"]; [db executeUpdate:@"INSERT INTO t_person(name, money) VALUES('LS', 1000)"]; }]; } - (IBAction)updateBtnClick { /* [self.queue inDatabase:^(FMDatabase *db) { [db beginTransaction]; // 开启事务 [db executeUpdate:@"update t_person set money = 0 where name = 'Zs';"]; // [db rollback];// 主动回滚 [db executeUpdate:@"update t_person set money = 2000 where name = 'LS';"]; [db commit];// 提交事务 }]; */ [self.queue inTransaction:^(FMDatabase *db, BOOL *rollback) { [db executeUpdate:@"update t_person set money = 0 where name = 'Zs';"]; NSLog(@"主动回滚"); *rollback = YES; [db executeUpdate:@"update t_person set money = 2000 where name = 'LS';"]; }]; } - (IBAction)deleteBtnClick { [self.queue inDatabase:^(FMDatabase *db) { BOOL success = [db executeUpdate:@"DELETE FROM t_student WHERE age < ?;", @50]; if (success) { NSLog(@"删除成功"); }else { NSLog(@"删除失败"); } }]; } - (IBAction)queryBtnClick { [self.queue inDatabase:^(FMDatabase *db) { // 1.查询 FMResultSet *set = [db executeQuery:@"SELECT * FROM t_student;"]; // 2.取出数据 while ([set next]) { NSString *name = [set stringForColumn:@"name"]; int age = [set intForColumn:@"age"]; NSLog(@"name = %@, age = %d", name, age); } }]; } @end