上一篇介绍了只能存储特定对象(即非自定义对象)的NSUserDefaults、wirteToFile:及Plist,但是这两种方式有局限,不能存储自定义对象。
下面总结一些可以存储自定义对象的方法,可以存储自定义对象的方法,也一定可以存储非自定义对象。
一、NSCoding (NSKeyedArchiver\NSKeyedUnarchiver)
归档:自定义对象转化为二进制流
反归档:二进制流转化为自定义对象
1、准备工作
(1)自定义一个Student类
//Student.h
@interface Student : NSObject<NSCoding>
@property(nonatomic,copy) NSString *name;
@property(nonatomic,assign) NSInteger age;
@property(nonatomic,copy)NSString *gender;
@end
//Student.m
@implementation Student
//序列化
-(void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeInteger:self.age forKey:@"age"];
[aCoder encodeObject:self.gender forKey:@"gender"];
}
//反序列化
-(instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self) {
self.name = [aDecoder decodeObjectForKey:@"name"];
self.age = [aDecoder decodeIntegerForKey:@"age"];
self.gender = [aDecoder decodeObjectForKey:@"gender"];
}
return self;
}
@end
//实例化自定义对象
Student *stu = [[Student alloc]init];
stu.name = @"leo";
stu.age = 26;
stu.gender = @"boy";
(2)获取路径方法
//获取文件路径方法
-(NSString *)returnFilePath:(NSString *)fileName
{
NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
NSString *finalPath = [path stringByAppendingPathComponent:fileName];
return finalPath;
}
2、一次性存储单个自定义对象或单个非自定义对象
(1)存储及读取对象的方法
//存储单个对象方法
-(void)saveSingleObject:(id)object toFile:(NSString *)filePath
{
BOOL isArchiver = [NSKeyedArchiver archiveRootObject:object toFile:filePath];
if (isArchiver) {
NSLog(@"SUCCESS");
}else{
NSLog(@"failure");
}
}
//读取单个对象的方法
-(id)readSingleObiectFromFile:(NSString *)filePath{
if (![[NSFileManager defaultManager]fileExistsAtPath:filePath]) {
return nil; //不存在文件路径
}else{
id object = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
return object;
}
}
(2)调用方法
//存储1:一次只能存储单个非自定义对象
NSString *firstPath = [self returnFilePath:@"arch1.txt"];
NSString *contentStr = @"科学的管理,合格的产品,优质的工程、满意的服务";
[self saveSingleObject:contentStr toFile:firstPath];
//读取1:
NSString *resultStr = [self readSingleObiectFromFile:firstPath];
if (resultStr == nil) {
NSLog(@"没有缓存");
}else{
NSLog(@"resultStr:%@",resultStr);
}
//调用2:一次行只能存储单个自定义对象
NSString *secondPath = [self returnFilePath:@"arch2.txt"];
[self saveSingleObject:stu toFile:secondPath];
//读取2:
Student *singleStu = [self readSingleObiectFromFile:secondPath];
NSLog(@"name:%@\nage:%ld\ngender:%@",singleStu.name,(long)singleStu.age,singleSt
3、一次性存储或读取多个自定义对象或非自定义对象
(1)存储多个对象
NSString *thirdPath = [self returnFilePath:@"arch3.txt"];
NSString *name = @"shasha";
int age = 24;
NSString *gender = @"girl";
BOOL isHappy = YES;
NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:data];
[archiver encodeObject:name forKey:@"name"];
[archiver encodeInt:age forKey:@"age"];
[archiver encodeBool:isHappy forKey:@"happy"];
[archiver encodeObject:gender forKey:@"gender"];
[archiver encodeObject:stu forKey:@"student"];
[archiver finishEncoding];
//将归档后的数据写入文件
BOOL isSaved = [data writeToFile:thirdPath atomically:YES];
if (isSaved) {
NSLog(@"success");
}else{
NSLog(@"error");
}
(2)读取多个对象
NSMutableData *resultData = [NSMutableData dataWithContentsOfFile:thirdPath];
NSKeyedUnarchiver *unarchiber = [[NSKeyedUnarchiver alloc]initForReadingWithData:resultData];
NSString *name2 = [unarchiber decodeObjectForKey:@"name"];
int age2 = [unarchiber decodeIntForKey:@"age"];
BOOL hpaay = [unarchiber decodeBoolForKey:@"happy"];
NSString *gen2 = [unarchiber decodeObjectForKey:@"gender"];
Student *someStu = [unarchiber decodeObjectForKey:@"student"];
[unarchiber finishDecoding];
NSLog(@"result:%@\n%d\n%u\n%@",name2,age2,hpaay,gen2);
NSLog(@"%@\n%ld\n%@",someStu.name,someStu.age,someStu.gender);
二、FMDB
1、概念
* (1)是ios平台的SQLite数据库框架
* (2)以OC的方式封装了SQLite的C语言API
2、优点:
*(1)使用起来更加面向对象,省去了很多冗余的C语言代码。
*(2)提供了多线程安全的数据库操作方法,有效地防止数据混乱。
*(3)对比苹果自带的Core Data框架,更加轻量级和灵活
3、常用类
*(1)FMDatabase:用来执行sql语句;一个FMDatabase对象就代表一个单独的sqlite数据库。FMDataBase这个类是线程不安全的,如果在多个线程中同时使用一个FMDatabase实例,会造成数据混乱的等问题。
*(2)FMResultSet:使用FMDatabase执行查询后的结果集
*(3)FMDatabaseQueue;用于在多个线程中执行查询或更新,是线程安全的
4、文件路径的类型
* (1)具体文件路径,如果不存在会自动创建
* (2)空字符串@"",会在临时目录创建一个空的数据库,当FMDatabase连接关闭时,数据库文件也被删除
* (3)nil,会创建一个内存中临时数据库,当FMDatabase连接关闭时,数据库会被销毁
5、打开数据库
//如果具体文件路径不存在,则会创建新的数据库
FMDatabase *db = [FMDatabase databaseWithPath:path];
if (![db open]) {
NSLog(@"数据库打开失败");
}else{
NSLog(@"创建或打开数据库成功");
}
6、执行查询
1)查询方法
- (FMResultSet*)executeQuery:(NSString*)sql, ...
- (FMResultSet*)executeQueryWithFormat:(NSString*)format, ...
- (FMResultSet*)executeQuery:(NSString*)sql withArgumentsInArray:(NSArray*)arguments
2)查询示例
//查询数据
FMResultSet *rs = [db executeQuery:@"select * from t_stu"];
if (rs == nil) {
NSLog(@"错误码:%@\n%d",[db lastErrorMessage],[db lastErrorCode]);
}
//遍历结果集
while ([rs next]) {
NSString *name = [rs stringForColumn:@"name"];
int age = [rs intForColumn:@"age"];
double score = [rs doubleForColumn:@"score"];
int _id = [rs intForColumnIndex:0];
NSString *_name = [rs stringForColumnIndex:1];
NSLog(@"name:%@\nage:%d\nscore:%f\n_id:%d\n_name:%@",name,age,score,_id,_name);
}
7、执行更新
除查询(select)以外的所有操作,都称为更新(create,drop,insert,update,delete)
1)更新方法
- (BOOL)executeUpdate:(NSString*)sql, ... //用于执行单个sql语句
- (BOOL)executeUpdateWithFormat:(NSString*)format, ...
- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray*)arguments
- (BOOL)executeStatements:(NSString *)sql //用于一次性执行多个sql语句,不接受参数值;
- (BOOL)executeStatements:(NSString *)sql withResultBlock:(FMDBExecuteStatementsCallbackBlock)block; //当sql语句为查询语句时,会走方法体内
2) 示例
BOOL success5= [db executeUpdate:@"update t_testmei set name = 'lele' where name = 'leo';"];
NSString *sql1 = @"create table if not exists bulktest1 (id integer primary key autoincrement, x text);"
"create table if not exists bulktest2 (id integer primary key autoincrement, y text);"
"insert into bulktest1 (x) values ('XXX');"
"insert into bulktest2 (y) values ('YYY');";
BOOL success1 = [db executeStatements:sql1];
//注意,int类型的数据必须转化为NSNmuber类型的对象!!!
BOOL success3 = [db executeUpdate:@"insert into t_testmei(name,age) values (?,?);",name1,@(age)];
if (!success3) {
NSLog(@"%@\n%d",db.lastErrorMessage,db.lastErrorCode);
}
BOOL success4 = [db executeUpdateWithFormat:@"insert into t_testmei(name,age) values (%@,%ld);",name2,age2];
NSString *sql3 = [NSString stringWithFormat:@"insert into t_testmei (name,age) values ('%@',%ld);",name1,age]; //注:单引号
BOOL success3 = [db executeUpdate:sql3];
BOOL sus40 = [db executeUpdate:@"insert into t_testmei(name,age) values (?,?);" withArgumentsInArray:@[@"lanyangyang",@6]];
NSDictionary *arguments = @{@"name":@"lala",@"age":@(arc4random_uniform(40))};
NSDictionary *arguments = @{@"name":@"lala",@"age":@(arc4random_uniform(40))};
BOOL sus41 = [db executeUpdate:@"insert into t_testmei(name,age) values (:name,:age);" withParameterDictionary:arguments];
8、FMDatabaseQueue的使用
在多个线程中执行查询或更新
FMDatabaseQueue *queeueDB = [FMDatabaseQueue databaseQueueWithPath:path];
//简单实用
[queeueDB inDatabase:^(FMDatabase *db) {
[db executeUpdate:@"insert into t_testmei(name) values (?)",@"Jack"];
[db executeUpdate:@"insert into t_testmei(name) values (?)",@"Rose"];
[ db executeUpdate:@"insert into t_testmei(name) values (?)",@"jim"];
FMResultSet *rs = [db executeQuery:@"select * from t_testmei"];
while ([rs next]) {
NSString *nameStr = [rs stringForColumn:@"name"];
NSLog(@"%@",nameStr);
}
}];
//使用事务
[queeueDB inTransaction:^(FMDatabase *db, BOOL *rollback) {
//注:rollback代表回滚
[db executeUpdate:@"insert into t_testmei(name) values (?)",@"tongbaby"];
[db executeUpdate:@"insert into t_testmei(name) values (?)",@"junbaby"];
[ db executeUpdate:@"insert into t_testmei(name) values (?)",@"chenbaby"];
FMResultSet *rs = [db executeQuery:@"select * from t_testmei"];
while ([rs next]) {
NSString *nameStr = [rs stringForColumn:@"name"];
NSLog(@"%@",nameStr);
}
}];
三、SQLite
1、概念
是一款轻型的嵌入式数据库(数据库是按照数据结构来组织、存储和管理数据的仓库)。
2、优点
占用资源非常低,在嵌入式设备中,可能只需要几百k的内存就够了。
处理速度很快。
四、coreData:
原理是对sqlite的封装,自动生成sql语句,对数据库进行操作。
但能自行扩展sql语句。