? ? 上一篇介紹了只能存儲特定對象(即非自定義對象)的NSUserDefaults、wirteToFile:及Plist,但是這兩種方式有局限,不能存儲自定義對象。
? ? 下面總結(jié)一些可以存儲自定義對象的方法,可以存儲自定義對象的方法,也一定可以存儲非自定義對象。
一、NSCoding (NSKeyedArchiver\NSKeyedUnarchiver)
歸檔:自定義對象轉(zhuǎn)化為二進(jìn)制流
反歸檔:二進(jìn)制流轉(zhuǎn)化為自定義對象
1、準(zhǔn)備工作
(1)自定義一個(gè)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
//實(shí)例化自定義對象
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、一次性存儲單個(gè)自定義對象或單個(gè)非自定義對象
(1)存儲及讀取對象的方法
//存儲單個(gè)對象方法
-(void)saveSingleObject:(id)object toFile:(NSString *)filePath
{
BOOL isArchiver = [NSKeyedArchiver archiveRootObject:object toFile:filePath];
if (isArchiver) {
NSLog(@"SUCCESS");
}else{
NSLog(@"failure");
}
}
//讀取單個(gè)對象的方法
-(id)readSingleObiectFromFile:(NSString *)filePath{
if (![[NSFileManager defaultManager]fileExistsAtPath:filePath]) {
return nil; //不存在文件路徑
}else{
id object = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
return object;
}
}
(2)調(diào)用方法
//存儲1:一次只能存儲單個(gè)非自定義對象
NSString *firstPath = [self returnFilePath:@"arch1.txt"];
NSString *contentStr = @"科學(xué)的管理,合格的產(chǎn)品,優(yōu)質(zhì)的工程、滿意的服務(wù)";
[self saveSingleObject:contentStr toFile:firstPath];
//讀取1:
NSString *resultStr = [self readSingleObiectFromFile:firstPath];
if (resultStr == ?nil) {
NSLog(@"沒有緩存");
}else{
NSLog(@"resultStr:%@",resultStr);
}
//調(diào)用2:一次行只能存儲單個(gè)自定義對象
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、一次性存儲或讀取多個(gè)自定義對象或非自定義對象
(1)存儲多個(gè)對象
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];
//將歸檔后的數(shù)據(jù)寫入文件
BOOL isSaved = ?[data writeToFile:thirdPath atomically:YES];
if (isSaved) {
NSLog(@"success");
}else{
NSLog(@"error");
}
(2)讀取多個(gè)對象
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數(shù)據(jù)庫框架
* (2)以O(shè)C的方式封裝了SQLite的C語言API
2、優(yōu)點(diǎn):
*(1)使用起來更加面向?qū)ο螅∪チ撕芏嗳哂嗟腃語言代碼。
*(2)提供了多線程安全的數(shù)據(jù)庫操作方法,有效地防止數(shù)據(jù)混亂。
*(3)對比蘋果自帶的Core Data框架,更加輕量級和靈活
3、常用類
*(1)FMDatabase:用來執(zhí)行sql語句;一個(gè)FMDatabase對象就代表一個(gè)單獨(dú)的sqlite數(shù)據(jù)庫。FMDataBase這個(gè)類是線程不安全的,如果在多個(gè)線程中同時(shí)使用一個(gè)FMDatabase實(shí)例,會造成數(shù)據(jù)混亂的等問題。
*(2)FMResultSet:使用FMDatabase執(zhí)行查詢后的結(jié)果集
*(3)FMDatabaseQueue;用于在多個(gè)線程中執(zhí)行查詢或更新,是線程安全的
4、文件路徑的類型
* (1)具體文件路徑,如果不存在會自動創(chuàng)建
* (2)空字符串@"",會在臨時(shí)目錄創(chuàng)建一個(gè)空的數(shù)據(jù)庫,當(dāng)FMDatabase連接關(guān)閉時(shí),數(shù)據(jù)庫文件也被刪除
* (3)nil,會創(chuàng)建一個(gè)內(nèi)存中臨時(shí)數(shù)據(jù)庫,當(dāng)FMDatabase連接關(guān)閉時(shí),數(shù)據(jù)庫會被銷毀
5、打開數(shù)據(jù)庫
//如果具體文件路徑不存在,則會創(chuàng)建新的數(shù)據(jù)庫
FMDatabase *db = [FMDatabase databaseWithPath:path];
if (![db open]) {
NSLog(@"數(shù)據(jù)庫打開失敗");
}else{
NSLog(@"創(chuàng)建或打開數(shù)據(jù)庫成功");
}
6、執(zhí)行查詢
1)查詢方法
- (FMResultSet*)executeQuery:(NSString*)sql, ...
- (FMResultSet*)executeQueryWithFormat:(NSString*)format, ...
- (FMResultSet*)executeQuery:(NSString*)sql withArgumentsInArray:(NSArray*)arguments
2)查詢示例
//查詢數(shù)據(jù)
FMResultSet *rs = [db executeQuery:@"select * from t_stu"];
if (rs == nil) {
NSLog(@"錯(cuò)誤碼:%@\n%d",[db lastErrorMessage],[db lastErrorCode]);
}
//遍歷結(jié)果集
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、執(zhí)行更新
除查詢(select)以外的所有操作,都稱為更新(create,drop,insert,update,delete)
1)更新方法
- (BOOL)executeUpdate:(NSString*)sql, ... ? ? ?//用于執(zhí)行單個(gè)sql語句
- (BOOL)executeUpdateWithFormat:(NSString*)format, ...
- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray*)arguments
- (BOOL)executeStatements:(NSString *)sql ?//用于一次性執(zhí)行多個(gè)sql語句,不接受參數(shù)值;
?- (BOOL)executeStatements:(NSString *)sql withResultBlock:(FMDBExecuteStatementsCallbackBlock)block; ?//當(dāng)sql語句為查詢語句時(shí),會走方法體內(nèi)
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類型的數(shù)據(jù)必須轉(zhuǎn)化為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的使用
在多個(gè)線程中執(zhí)行查詢或更新
FMDatabaseQueue *queeueDB = [FMDatabaseQueue databaseQueueWithPath:path];
//簡單實(shí)用
[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);
}
}];
//使用事務(wù)
[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、概念
是一款輕型的嵌入式數(shù)據(jù)庫(數(shù)據(jù)庫是按照數(shù)據(jù)結(jié)構(gòu)來組織、存儲和管理數(shù)據(jù)的倉庫)。
2、優(yōu)點(diǎn)
占用資源非常低,在嵌入式設(shè)備中,可能只需要幾百k的內(nèi)存就夠了。
處理速度很快。
四、coreData:
原理是對sqlite的封裝,自動生成sql語句,對數(shù)據(jù)庫進(jìn)行操作。
但能自行擴(kuò)展sql語句。