一、歸檔介紹
1.歸檔是指用某種格式來保存一個或多個對象,以便以后還原這些對象的過程。歸檔是將數(shù)據(jù)持久化的一種方式(所謂數(shù)據(jù)持久化,就是指在IOS開發(fā)過程中,將數(shù)據(jù)保存到本地,能夠讓程序的運行更加流暢)。
2.想要歸檔的數(shù)據(jù)對象,需要遵守NSCoding協(xié)議,并且該對象對應(yīng)的類必須提供encodeWithCoder:和initWithCoder:方法。
3.歸檔就是將臨時數(shù)據(jù)保存成本地文件。
4.歸檔的缺點:歸檔的形式來保存數(shù)據(jù),只能一次性歸檔保存以及一次性解壓。所以只能針對小量數(shù)據(jù),而且對數(shù)據(jù)操作比較笨拙,即如果想改動數(shù)據(jù)的某一小部分,還是需要解壓整個數(shù)據(jù)或者歸檔整個數(shù)據(jù)。
二、XML歸檔
1.局限:數(shù)據(jù)類型只支持 NSString、NSDictionary、NSArayy、NSData、NSNumber(如果你想的話,可以將基本數(shù)據(jù)類型轉(zhuǎn)換為NSNumber再進行歸檔)。
2.比較方便,設(shè)置好歸檔路徑,一句話歸檔,一句話解檔。
3.歸檔文件格式:一般保存.plist文件。
/**** NSString和NSMutableString XML歸解檔 ****/NSString*str =@"hello world";
NSString*path = [[NSHomeDirectory() stringByAppendingPathComponent:@"Desktop"]stringByAppendingPathComponent:@"hello.txt"];//atomically:這個參數(shù)意思是如果為YES,則保證文件的寫入原子性。就是說會先創(chuàng)建一個臨時文件,直到文件內(nèi)容寫入成功再導(dǎo)入到目標(biāo)文件里.如果為NO,則直接寫入目標(biāo)文件里.[str writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];//這里會覆蓋原來的內(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歸解檔 ****///任何對象都可以轉(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.將各種類型的對象存儲到文件中,而且不僅僅是字符串、數(shù)組和字典類型,有一種更靈括的方法。就是利用NSKeyedArchiver類創(chuàng)建帶鍵(keyed)的檔案來完成。實現(xiàn)對我們自定義的類進行歸檔。
2.序列化與反序列化:將一個Objective-C對象轉(zhuǎn)換成NSData的操作叫做對象的序列化;而將一個NSData轉(zhuǎn)換成Objective-C對象的操作叫做對象的反序列化。一個Objective-C對象需要通過實現(xiàn)NSCoding協(xié)議以便支持序列化與反序列化
3.模擬場景:有一個學(xué)生類,學(xué)生擁有三個屬性name、age、book(一本書),其中book對應(yīng)Book類,Book類中擁有一個屬性bookName,歸檔一個數(shù)組,數(shù)組中有兩個student對象。
Student類
#import
#import"Book.h"@interfaceStudent : NSObject@property (nonatomic,copy)NSString*name;
@property (nonatomic,assign)intage;//除Student類之外,這里有一個自定義類型Book,所以Book類也需要實現(xiàn)NSCoding協(xié)議,從而進行歸檔@property (nonatomic,strong)Book *book;@end#import"Student.h"@implementationStudent-(void)encodeWithCoder:(NSCoder *)aCoder
{//歸檔姓名(NSString 對象)[aCoder encodeObject:self.name forKey:@"name"];//歸檔年齡(基本數(shù)據(jù)類型,如果是其它基本數(shù)據(jù)類型調(diào)用相應(yīng)的encode方法)[aCoder encodeInt:self.age forKey:@"age"];//歸檔自定義類(Book)[aCoder encodeObject:self.book forKey:@"book"];
}-(instancetype)initWithCoder:(NSCoder *)aDecoder
{if(self =[super init])
{//歸檔的key 寫的什么 對應(yīng)屬性解檔key就寫什么self.name = [aDecoder decodeObjectForKey:@"name"];
self.age= [aDecoder decodeInt32ForKey:@"age"];
self.book= [aDecoder decodeObjectForKey:@"book"];
}returnself;
}@end
同樣的,Book類也要實現(xiàn)
協(xié)議并重寫相應(yīng)的兩個方法。
NSKeyedArchiver歸檔實現(xiàn)代碼:
//這里student、book對象初始化的代碼就不列了NSArray *stuArr =@[stu1,stu2];if([NSKeyedArchiver archiveRootObject:stuArr toFile:path5])
{
NSLog(@"寫入成功");
}
NSArray*arr = [NSKeyedUnarchiver unarchiveObjectWithFile:path5];
如此,便可以實現(xiàn)自定義對象的歸檔和解檔了。
四、NSUserDefaults
1.NSUserDefaults是一個單例類,如它的名字一樣,用于永久保存一些用戶對于應(yīng)用程序的配置之類的簡單數(shù)據(jù),其簡單而又實用
2.NSUserDefaults支持的數(shù)據(jù)類型同XML歸檔一樣,僅僅用于保存一些程序配置信息的話完全是可以勝任的。
//保存NSString *passWord =@"88888888";
NSUserDefaults*user =[NSUserDefaults standardUserDefaults];
[user setObject:passWord forKey:@"passWord"];//通過存儲時候key取出相應(yīng)的valueNSString *passWord = [ user objectForKey:@"passWord"];
3.當(dāng)然,NSUserDefaults也可以存儲自定義類,同NSKeyedArchiver歸檔相似,為自定義類實現(xiàn)
協(xié)議,然后
//將student類型變?yōu)镹SData類型 (這里采用NSKeyedArchiver中的例子Student為例)NSData *data = [NSKeyedArchiver archivedDataWithRootObject:student];
// NSUserDefaults是支持NSData類型
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
[user setObject:data forKey:@"student"];
五、由sqlite到FMDB
1.使用sqlite之前需要了解一下基本的一些sql語句,很簡單,學(xué)會建表、增刪改查的語句就行了。(學(xué)習(xí)的話這里推薦火狐瀏覽器下的sqlite組件)
2.使用:在工程中導(dǎo)入包“l(fā)ibsqlite3.dylib”,在類中導(dǎo)入頭文件#import
Xcode7注意了,當(dāng)你去導(dǎo)入sqlite3.dylib的時候(其實那兩個.tbd文件就是以前老版本的替代了),你會發(fā)現(xiàn)根本找不到這個包,因為這個包自xcode7之后就被蘋果隱藏掉了
如果你想要使用老版本的,請繼續(xù)下面的操作。
當(dāng)點擊“+”彈出窗口之后,選擇“add other”,快捷鍵 CMD+Shift+G (Go to the folder),輸入/usr/lib后,進入隱藏的界面,在文件目錄下找到,然后添加你需要的 *.dylib,如libsqlite3.dylib文件。
3.sqlite使用,這里講一下我之前做的一個增刪改查的demo,下面貼上代碼
User類:
#import
@interfaceUser : NSObject
@property (nonatomic,retain)NSData*icon;//頭像@property (nonatomic,copy)NSString *name;//名字@property (nonatomic,copy)NSString *phone;//電話號碼@property (nonatomic,assign)intage;//年齡@property (nonatomic,assign)NSInteger ID;@end
UserDBManager類
////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;//查詢所有-(NSArray *)queryUser;//通過姓名查詢用戶-(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])
{//如果存在就打開boolresult = sqlite3_open([dbPath UTF8String], &_dataBase) ==SQLITE_OK;if(result)
{returnYES;
}else{
sqlite3_close(_dataBase);returnNO;
}
}else{//打開數(shù)據(jù)庫 返回值sqlite_ok 代表打開成功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語句sqlite3_stmt *stateMent;//解析sql語句? 第一個 數(shù)據(jù)庫變量? 第二個sql語句? sql語句的長度 -1代表自動計算? stetement變量intpResult =? sqlite3_prepare_v2(_dataBase, [sql UTF8String], -1, &stateMent, nil);//解析sql 語句失敗if(pResult !=SQLITE_OK)
{
NSLog(@"創(chuàng)建表失敗");
}else{//執(zhí)行sql 語句 成功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語句? 第一個 數(shù)據(jù)庫變量? 第二個sql語句? sql語句的長度 -1代表自動計算? stetement變量intresult = sqlite3_prepare_v2(_dataBase, [addSql UTF8String], -1, &stateMent, nil);//給sql語句里的’?‘? 賦值? 第一個參數(shù)是statement 第二個是‘?’的位置 以1開頭//姓名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 語句 成功if(sqlite3_step(stateMent) ==SQLITE_DONE)
{
NSLog(@"插入成功");
}else{
NSLog(@"插入失敗");
}
}//釋放statementsqlite3_finalize(stateMent);//關(guān)閉數(shù)據(jù)庫sqlite3_close(_dataBase);returnYES;
}returnNO;
}-(BOOL)delePerson:(NSInteger)idd
{if([self openDB])
{
NSString*deleSql = [NSString stringWithFormat:@"delete from User where id = %ld",idd];//通過id刪除user表中的用戶數(shù)據(jù)sqlite3_stmt *stateMent;intresult = sqlite3_prepare_v2(_dataBase, [deleSql UTF8String], -1, &stateMent, nil);if(result ==SQLITE_OK)
{//執(zhí)行sql 語句 成功if(sqlite3_step(stateMent) ==SQLITE_DONE)
{
NSLog(@"刪除成功");
}else{
NSLog(@"刪除失敗");
}
}//釋放statementsqlite3_finalize(stateMent);//關(guān)閉數(shù)據(jù)庫sqlite3_close(_dataBase);returnYES;
}returnNO;
}-(NSArray *)queryUser
{
NSMutableArray*arr;if([self openDB])
{
arr= [NSMutableArray arrayWithCapacity:0];
NSString*sql =@"select * from User";//sql 語句:查詢User表中的所有數(shù)據(jù)sqlite3_stmt *statement;//解析sql語句? 第一個 數(shù)據(jù)庫變量? 第二個sql語句? sql語句的長度 -1代表自動計算? stetement變量intpResult =? sqlite3_prepare_v2(_dataBase, [sql UTF8String], -1, &statement, nil);//解析sql語句成功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ù)庫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語句:%@",sql);
sqlite3_stmt*statement;//解析sql語句? 第一個 數(shù)據(jù)庫變量? 第二個sql語句? sql語句的長度 -1代表自動計算? stetement變量intpResult =? sqlite3_prepare_v2(_dataBase, [sql UTF8String], -1, &statement, nil);//解析sql語句成功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ù)庫sqlite3_close(_dataBase);
}returnarr;
}@end
// 修改用戶數(shù)據(jù)的好像當(dāng)時懶得做,并沒有實現(xiàn)那個方法,看懂了另外幾個增、查、刪的實現(xiàn)也就差不多了,基本操作數(shù)據(jù)庫的流程都一樣,只是執(zhí)行不同的sql語句而已。