一题诵、歸檔介紹
1.歸檔是指用某種格式來(lái)保存一個(gè)或多個(gè)對(duì)象渣淳,以便以后還原這些對(duì)象的過(guò)程梢睛。歸檔是將數(shù)據(jù)持久化的一種方式(所謂數(shù)據(jù)持久化肥印,就是指在IOS開(kāi)發(fā)過(guò)程中识椰,將數(shù)據(jù)保存到本地,能夠讓程序的運(yùn)行更加流暢)深碱。
2.想要?dú)w檔的數(shù)據(jù)對(duì)象腹鹉,需要遵守NSCoding協(xié)議,并且該對(duì)象對(duì)應(yīng)的類(lèi)必須提供encodeWithCoder:和initWithCoder:方法敷硅。
3.歸檔就是將臨時(shí)數(shù)據(jù)保存成本地文件功咒。
4.歸檔的缺點(diǎn):歸檔的形式來(lái)保存數(shù)據(jù),只能一次性歸檔保存以及一次性解壓绞蹦。所以只能針對(duì)小量數(shù)據(jù)力奋,而且對(duì)數(shù)據(jù)操作比較笨拙,即如果想改動(dòng)數(shù)據(jù)的某一小部分幽七,還是需要解壓整個(gè)數(shù)據(jù)或者歸檔整個(gè)數(shù)據(jù)景殷。
二、XML歸檔
1.局限:數(shù)據(jù)類(lèi)型只支持 NSString锉走、NSDictionary滨彻、NSArayy、NSData挪蹭、NSNumber(如果你想的話亭饵,可以將基本數(shù)據(jù)類(lèi)型轉(zhuǎn)換為NSNumber再進(jìn)行歸檔)。
2.比較方便梁厉,設(shè)置好歸檔路徑辜羊,一句話歸檔,一句話解檔词顾。
3.歸檔文件格式:一般保存.plist文件八秃。
/**** NSString和NSMutableString XML歸解檔 ****/NSString*str =@"hello world";
NSString*path = [[NSHomeDirectory() stringByAppendingPathComponent:@"Desktop"]stringByAppendingPathComponent:@"hello.txt"];//atomically:這個(gè)參數(shù)意思是如果為YES,則保證文件的寫(xiě)入原子性肉盹。就是說(shuō)會(huì)先創(chuàng)建一個(gè)臨時(shí)文件,直到文件內(nèi)容寫(xiě)入成功再導(dǎo)入到目標(biāo)文件里.如果為NO,則直接寫(xiě)入目標(biāo)文件里.[str writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];//這里會(huì)覆蓋原來(lái)的內(nèi)容[@"hello world 2"writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];
NSString*str2 = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
/**** NSData和NSMutableData XML歸解檔 ****///任何對(duì)象都可以轉(zhuǎn)化為NSDataNSData *data = [@"hello world"dataUsingEncoding:NSUTF8StringEncoding];
NSString*path2 = [[NSHomeDirectory() stringByAppendingPathComponent:@"Desktop"]stringByAppendingPathComponent:@"data.txt"];//歸檔[data writeToFile:path2 atomically:YES];//解檔[NSData dataWithContentsOfFile:path2];
/**** NSArray及NSMutableArray XML歸解檔 ****/
NSArray*array = @[@"test",@"test2"];
NSString *path3 = [[NSHomeDirectory() stringByAppendingPathComponent:@"Desktop"]stringByAppendingPathComponent:@"array.plist"];//歸檔[array writeToFile:path3 atomically:YES];// 解檔NSArray *array = [NSArray arrayWithContentsOfFile:path3];
/**** NSArray XML歸解檔 ****/NSDictionary*dic = [NSDictionary dictionaryWithObjectsAndKeys:@"one",@"1",@"two",@"2", nil];
NSString*path4 = [[NSHomeDirectory() stringByAppendingPathComponent:@"Desktop"]stringByAppendingPathComponent:@"dic.plist"];//歸檔[dic writeToFile:path4 atomically:YES];//解檔NSDictionary *ddic = [NSDictionary dictionaryWithContentsOfFile:path3];
三昔驱、NSKeyedArchiver歸檔
1.將各種類(lèi)型的對(duì)象存儲(chǔ)到文件中,而且不僅僅是字符串上忍、數(shù)組和字典類(lèi)型骤肛,有一種更靈括的方法。就是利用NSKeyedArchiver類(lèi)創(chuàng)建帶鍵(keyed)的檔案來(lái)完成窍蓝。實(shí)現(xiàn)對(duì)我們自定義的類(lèi)進(jìn)行歸檔腋颠。
2.序列化與反序列化:將一個(gè)Objective-C對(duì)象轉(zhuǎn)換成NSData的操作叫做對(duì)象的序列化;而將一個(gè)NSData轉(zhuǎn)換成Objective-C對(duì)象的操作叫做對(duì)象的反序列化吓笙。一個(gè)Objective-C對(duì)象需要通過(guò)實(shí)現(xiàn)NSCoding協(xié)議以便支持序列化與反序列化
3.模擬場(chǎng)景:有一個(gè)學(xué)生類(lèi)淑玫,學(xué)生擁有三個(gè)屬性name、age、book(一本書(shū))絮蒿,其中book對(duì)應(yīng)Book類(lèi)尊搬,Book類(lèi)中擁有一個(gè)屬性bookName,歸檔一個(gè)數(shù)組土涝,數(shù)組中有兩個(gè)student對(duì)象毁嗦。
Student類(lèi)
#import
#import"Book.h"@interfaceStudent : NSObject@property (nonatomic,copy)NSString*name;
@property (nonatomic,assign)intage;//除Student類(lèi)之外,這里有一個(gè)自定義類(lèi)型Book回铛,所以Book類(lèi)也需要實(shí)現(xiàn)NSCoding協(xié)議,從而進(jìn)行歸檔@property (nonatomic,strong)Book *book;@end#import"Student.h"@implementationStudent-(void)encodeWithCoder:(NSCoder *)aCoder
{//歸檔姓名(NSString 對(duì)象)[aCoder encodeObject:self.name forKey:@"name"];//歸檔年齡(基本數(shù)據(jù)類(lèi)型克锣,如果是其它基本數(shù)據(jù)類(lèi)型調(diào)用相應(yīng)的encode方法)[aCoder encodeInt:self.age forKey:@"age"];//歸檔自定義類(lèi)(Book)[aCoder encodeObject:self.book forKey:@"book"];
}-(instancetype)initWithCoder:(NSCoder *)aDecoder
{if(self =[super init])
{//歸檔的key 寫(xiě)的什么 對(duì)應(yīng)屬性解檔key就寫(xiě)什么self.name = [aDecoder decodeObjectForKey:@"name"];
self.age= [aDecoder decodeInt32ForKey:@"age"];
self.book= [aDecoder decodeObjectForKey:@"book"];
}returnself;
}@end
同樣的茵肃,Book類(lèi)也要實(shí)現(xiàn)
協(xié)議并重寫(xiě)相應(yīng)的兩個(gè)方法。
NSKeyedArchiver歸檔實(shí)現(xiàn)代碼:
//這里student袭祟、book對(duì)象初始化的代碼就不列了NSArray *stuArr =@[stu1,stu2];if([NSKeyedArchiver archiveRootObject:stuArr toFile:path5])
{
NSLog(@"寫(xiě)入成功");
}
NSArray*arr = [NSKeyedUnarchiver unarchiveObjectWithFile:path5];
如此验残,便可以實(shí)現(xiàn)自定義對(duì)象的歸檔和解檔了。
四巾乳、NSUserDefaults
1.NSUserDefaults是一個(gè)單例類(lèi)您没,如它的名字一樣,用于永久保存一些用戶(hù)對(duì)于應(yīng)用程序的配置之類(lèi)的簡(jiǎn)單數(shù)據(jù)胆绊,其簡(jiǎn)單而又實(shí)用
2.NSUserDefaults支持的數(shù)據(jù)類(lèi)型同XML歸檔一樣氨鹏,僅僅用于保存一些程序配置信息的話完全是可以勝任的。
//保存NSString *passWord =@"88888888";
NSUserDefaults*user =[NSUserDefaults standardUserDefaults];
[user setObject:passWord forKey:@"passWord"];//通過(guò)存儲(chǔ)時(shí)候key取出相應(yīng)的valueNSString *passWord = [ user objectForKey:@"passWord"];
3.當(dāng)然压状,NSUserDefaults也可以存儲(chǔ)自定義類(lèi)仆抵,同NSKeyedArchiver歸檔相似,為自定義類(lèi)實(shí)現(xiàn)
協(xié)議种冬,然后
//將student類(lèi)型變?yōu)镹SData類(lèi)型 (這里采用NSKeyedArchiver中的例子Student為例)NSData *data = [NSKeyedArchiver archivedDataWithRootObject:student];
// NSUserDefaults是支持NSData類(lèi)型
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
[user setObject:data forKey:@"student"];
五镣丑、由sqlite到FMDB
1.使用sqlite之前需要了解一下基本的一些sql語(yǔ)句,很簡(jiǎn)單娱两,學(xué)會(huì)建表莺匠、增刪改查的語(yǔ)句就行了。(學(xué)習(xí)的話這里推薦火狐瀏覽器下的sqlite組件)
2.使用:在工程中導(dǎo)入包“l(fā)ibsqlite3.dylib”十兢,在類(lèi)中導(dǎo)入頭文件#import
Xcode7注意了趣竣,當(dāng)你去導(dǎo)入sqlite3.dylib的時(shí)候(其實(shí)那兩個(gè).tbd文件就是以前老版本的替代了),你會(huì)發(fā)現(xiàn)根本找不到這個(gè)包纪挎,因?yàn)檫@個(gè)包自xcode7之后就被蘋(píng)果隱藏掉了
如果你想要使用老版本的期贫,請(qǐng)繼續(xù)下面的操作。
當(dāng)點(diǎn)擊“+”彈出窗口之后异袄,選擇“add other”通砍,快捷鍵 CMD+Shift+G (Go to the folder),輸入/usr/lib后,進(jìn)入隱藏的界面封孙,在文件目錄下找到迹冤,然后添加你需要的 *.dylib,如libsqlite3.dylib文件虎忌。
3.sqlite使用泡徙,這里講一下我之前做的一個(gè)增刪改查的demo,下面貼上代碼
User類(lèi):
#import
@interfaceUser : NSObject
@property (nonatomic,retain)NSData*icon;//頭像@property (nonatomic,copy)NSString *name;//名字@property (nonatomic,copy)NSString *phone;//電話號(hào)碼@property (nonatomic,assign)intage;//年齡@property (nonatomic,assign)NSInteger ID;@end
UserDBManager類(lèi)
////UserDBManager.h//Sqlite3基礎(chǔ)操作////Created by silence on 15-8-15.//Copyright (c) 2015年 hawode06. All rights reserved.//#import
#import#import"User.h"#defineinsert @"INSERT"@interfaceUserDBManager : NSObject//插入數(shù)據(jù)-(BOOL)insertUser:(User *)user;//刪除數(shù)據(jù)-(BOOL)delePerson:(NSInteger)idd;//修改數(shù)據(jù)-(BOOL)updatePerson:(User *)User;//查詢(xún)所有-(NSArray *)queryUser;//通過(guò)姓名查詢(xún)用戶(hù)-(NSArray *)searchWithName:(NSString *)str;@end////UserDBManager.m//Sqlite3基礎(chǔ)操作////Created by silence on 15-8-15.//Copyright (c) 2015年 hawode06. All rights reserved.//#import"UserDBManager.h"@interfaceUserDBManager ()
@property (nonatomic,copy)NSString*dbPath;
@property (nonatomic,assign)sqlite3*dataBase;@end@implementationUserDBManager-(BOOL)openDB
{
NSString*path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString*dbPath = [path stringByAppendingPathComponent:@"user.db"];
NSLog(@"%@",dbPath);
NSFileManager*fm =[NSFileManager defaultManager];if([fm fileExistsAtPath:dbPath])
{//如果存在就打開(kāi)boolresult = sqlite3_open([dbPath UTF8String], &_dataBase) ==SQLITE_OK;if(result)
{returnYES;
}else{
sqlite3_close(_dataBase);returnNO;
}
}else{//打開(kāi)數(shù)據(jù)庫(kù) 返回值sqlite_ok 代表打開(kāi)成功if(sqlite3_open([dbPath UTF8String], &_dataBase) ==SQLITE_OK)
{
NSString*sql =@"create table? if not exists \"User\"(\"id\" INTEGER PRIMARY KEY? AUTOINCREMENT? NOT NULL? UNIQUE,\"name\" varchar,\"phone\" varchar,\"age\" INTEGER NOT NULL DEFAULT 1,\"image\" blob)";//執(zhí)行創(chuàng)建表的sql語(yǔ)句sqlite3_stmt *stateMent;//解析sql語(yǔ)句? 第一個(gè) 數(shù)據(jù)庫(kù)變量? 第二個(gè)sql語(yǔ)句? sql語(yǔ)句的長(zhǎng)度 -1代表自動(dòng)計(jì)算? stetement變量intpResult =? sqlite3_prepare_v2(_dataBase, [sql UTF8String], -1, &stateMent, nil);//解析sql 語(yǔ)句失敗if(pResult !=SQLITE_OK)
{
NSLog(@"創(chuàng)建表失敗");
}else{//執(zhí)行sql 語(yǔ)句 成功if(sqlite3_step(stateMent) ==SQLITE_DONE)
{
NSLog(@"創(chuàng)建表成功");
}else{
NSLog(@"創(chuàng)建表失敗");
}
}//釋放statementsqlite3_finalize(stateMent);returnYES;
}else{
sqlite3_close(_dataBase);returnNO;
}
}returnYES;
}-(BOOL)insertUser:(User *)user
{if([self openDB])
{
NSString*addSql =@"insert into User (name,phone,age,image) values (?,?,?,?)";
sqlite3_stmt*stateMent;//解析sql語(yǔ)句? 第一個(gè) 數(shù)據(jù)庫(kù)變量? 第二個(gè)sql語(yǔ)句? sql語(yǔ)句的長(zhǎng)度 -1代表自動(dòng)計(jì)算? stetement變量intresult = sqlite3_prepare_v2(_dataBase, [addSql UTF8String], -1, &stateMent, nil);//給sql語(yǔ)句里的’?‘? 賦值? 第一個(gè)參數(shù)是statement 第二個(gè)是‘?’的位置 以1開(kāi)頭//姓名sqlite3_bind_text(stateMent,1, [user.name UTF8String], -1, SQLITE_TRANSIENT);//電話sqlite3_bind_text(stateMent,2, [user.phone UTF8String], -1, SQLITE_TRANSIENT);//年齡sqlite3_bind_int(stateMent,3, user.age);//頭像sqlite3_bind_blob(stateMent,4, [user.icon bytes], (int)user.icon.length, nil);if(result ==SQLITE_OK)
{//執(zhí)行sql 語(yǔ)句 成功if(sqlite3_step(stateMent) ==SQLITE_DONE)
{
NSLog(@"插入成功");
}else{
NSLog(@"插入失敗");
}
}//釋放statementsqlite3_finalize(stateMent);//關(guān)閉數(shù)據(jù)庫(kù)sqlite3_close(_dataBase);returnYES;
}returnNO;
}-(BOOL)delePerson:(NSInteger)idd
{if([self openDB])
{
NSString*deleSql = [NSString stringWithFormat:@"delete from User where id = %ld",idd];//通過(guò)id刪除user表中的用戶(hù)數(shù)據(jù)sqlite3_stmt *stateMent;intresult = sqlite3_prepare_v2(_dataBase, [deleSql UTF8String], -1, &stateMent, nil);if(result ==SQLITE_OK)
{//執(zhí)行sql 語(yǔ)句 成功if(sqlite3_step(stateMent) ==SQLITE_DONE)
{
NSLog(@"刪除成功");
}else{
NSLog(@"刪除失敗");
}
}//釋放statementsqlite3_finalize(stateMent);//關(guān)閉數(shù)據(jù)庫(kù)sqlite3_close(_dataBase);returnYES;
}returnNO;
}-(NSArray *)queryUser
{
NSMutableArray*arr;if([self openDB])
{
arr= [NSMutableArray arrayWithCapacity:0];
NSString*sql =@"select * from User";//sql 語(yǔ)句:查詢(xún)User表中的所有數(shù)據(jù)sqlite3_stmt *statement;//解析sql語(yǔ)句? 第一個(gè) 數(shù)據(jù)庫(kù)變量? 第二個(gè)sql語(yǔ)句? sql語(yǔ)句的長(zhǎng)度 -1代表自動(dòng)計(jì)算? stetement變量intpResult =? sqlite3_prepare_v2(_dataBase, [sql UTF8String], -1, &statement, nil);//解析sql語(yǔ)句成功if(pResult ==SQLITE_OK)
{while(sqlite3_step(statement) ==SQLITE_ROW)
{
User*user =[[User alloc] init];intnum = sqlite3_column_int(statement,0);char*cName = (char*)sqlite3_column_text(statement,1);char*cPhone = (char*)sqlite3_column_text(statement,2);intage = sqlite3_column_int(statement,3);char*iconBytes = (char*)sqlite3_column_blob(statement,4);
NSInteger iconDataLen= sqlite3_column_bytes(statement,4);
user.name=[NSString stringWithCString:cName encoding:NSUTF8StringEncoding];
user.phone=[NSString stringWithCString:cPhone encoding:NSUTF8StringEncoding];
user.age=age;
user.icon=[NSData dataWithBytes:iconBytes length:iconDataLen];
user.ID=num;
[arr addObject:user];
}//釋放statementsqlite3_finalize(statement);
}//關(guān)閉數(shù)據(jù)庫(kù)sqlite3_close(_dataBase);
}returnarr;
}-(NSArray *)searchWithName:(NSString *)str
{
NSMutableArray*arr;if([self openDB])
{
arr= [NSMutableArray arrayWithCapacity:0];
NSString*sql = [NSString stringWithFormat:@"select * from User where name like '%%%@%%'",str];
NSLog(@"sql語(yǔ)句:%@",sql);
sqlite3_stmt*statement;//解析sql語(yǔ)句? 第一個(gè) 數(shù)據(jù)庫(kù)變量? 第二個(gè)sql語(yǔ)句? sql語(yǔ)句的長(zhǎng)度 -1代表自動(dòng)計(jì)算? stetement變量intpResult =? sqlite3_prepare_v2(_dataBase, [sql UTF8String], -1, &statement, nil);//解析sql語(yǔ)句成功if(pResult ==SQLITE_OK)
{while(sqlite3_step(statement) ==SQLITE_ROW)
{
User*user =[[User alloc] init];intnum = sqlite3_column_int(statement,0);char*cName = (char*)sqlite3_column_text(statement,1);char*cPhone = (char*)sqlite3_column_text(statement,2);intage = sqlite3_column_int(statement,3);char*iconBytes = (char*)sqlite3_column_blob(statement,4);
NSInteger iconDataLen= sqlite3_column_bytes(statement,4);
user.name=[NSString stringWithCString:cName encoding:NSUTF8StringEncoding];
user.phone=[NSString stringWithCString:cPhone encoding:NSUTF8StringEncoding];
user.age=age;
user.icon=[NSData dataWithBytes:iconBytes length:iconDataLen];
user.ID=num;
[arr addObject:user];
}
NSLog(@"數(shù)組%@",arr);//釋放statementsqlite3_finalize(statement);
}//關(guān)閉數(shù)據(jù)庫(kù)sqlite3_close(_dataBase);
}returnarr;
}@end
// 修改用戶(hù)數(shù)據(jù)的好像當(dāng)時(shí)懶得做膜蠢,并沒(méi)有實(shí)現(xiàn)那個(gè)方法堪藐,看懂了另外幾個(gè)增、查挑围、刪的實(shí)現(xiàn)也就差不多了礁竞,基本操作數(shù)據(jù)庫(kù)的流程都一樣,只是執(zhí)行不同的sql語(yǔ)句而已杉辙。