IOS 數(shù)據(jù)持久化的各種方式
1.plist文件存儲(chǔ)
?每個(gè)iOS應(yīng)用都有自己的應(yīng)用沙盒(應(yīng)用沙盒就是文件系統(tǒng)目錄),與其他文件系統(tǒng)隔離。應(yīng)用必須待在自己的沙盒里,其他應(yīng)用不能訪問該沙盒
應(yīng)用沙盒的文件系統(tǒng)目錄,如下圖所示(假設(shè)應(yīng)用的名稱叫Layer)

模擬器應(yīng)用沙盒的根路徑在: (apple是用戶名, 6.0是模擬器版本)
/Users/apple/Library/Application Support/iPhone Simulator/6.0/Applications
Document?保存應(yīng)用運(yùn)行時(shí)生成的需要持久化的數(shù)據(jù),iTunes同步設(shè)備時(shí)會(huì)備份該目錄。例如,游戲應(yīng)用可將游戲存檔保存在該目錄
temp?保存應(yīng)用運(yùn)行時(shí)所需的臨時(shí)數(shù)據(jù),使用完畢后再將相應(yīng)的文件從該目錄刪除。應(yīng)用沒有運(yùn)行時(shí),系統(tǒng)也可能會(huì)清除該目錄下的文件。iTunes同步設(shè)備時(shí)不會(huì)備份該目錄
Library/Caches?保存應(yīng)用運(yùn)行時(shí)生成的需要持久化的數(shù)據(jù),iTunes同步設(shè)備時(shí)不會(huì)備份該目錄。一般存儲(chǔ)體積大、不需要備份的非重要數(shù)據(jù)
Library/Preference:?保存應(yīng)用的所有偏好設(shè)置,iOS的Settings(設(shè)置)應(yīng)用會(huì)在該目錄中查找應(yīng)用的設(shè)置信息。iTunes同步設(shè)備時(shí)會(huì)備份該目錄
下面是示例代碼:
1/** 保存數(shù)據(jù)*/ 2- (IBAction)saveBtn 3{ 4NSLog(@"保存"); 5//1.獲取沙盒根路徑 6NSString *homePath = NSHomeDirectory(); 7//2.document路徑 8NSString *path = [homePath stringByAppendingPathComponent:@"Documents"]; 9//3.新建數(shù)據(jù)10NSArray *array = [NSArray arrayWithObjects:@"nan",@(22), nil];11NSDictionary *dict = @{@"sss":@"sddd",@"ssssaw":@(1222)};121314//4.存儲(chǔ)數(shù)據(jù)15NSString *fullPath1 = [path stringByAppendingPathComponent:@"data1.plist"];16NSString *fullPath2 = [path stringByAppendingPathComponent:@"data2.plist"];1718[array writeToFile:fullPath1 atomically:YES];//數(shù)組寫入plist19? ? [dict writeToFile:fullPath2 atomically:YES];2021NSLog(@"dict - %@",dict);22}2324/** 讀取數(shù)據(jù)*/25- (IBAction)readBtn26{27//1.獲取home目錄28NSString *home = NSHomeDirectory();29//2.拼接Document目錄30NSString *path = [home stringByAppendingPathComponent:@"Documents"];31//3.文件路徑32NSString *filePath1 = [path stringByAppendingPathComponent:@"data1.plist"];33NSString *filePath2 = [path stringByAppendingPathComponent:@"data2.plist"];34//讀取文件35NSArray *array = [NSArray arrayWithContentsOfFile:filePath1];36NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:filePath2];37NSLog(@"array - %@, dict - %@",array , dict);38}
缺點(diǎn):只能存儲(chǔ)含有?writeToFile:方法的對(duì)象,如NSDictionary,NSArray等.
2.偏好設(shè)置 -- 存放目錄?Library/Preference:
很多iOS應(yīng)用都支持偏好設(shè)置,比如保存用戶名、密碼、字體大小等設(shè)置,iOS提供了一套標(biāo)準(zhǔn)的解決方案來為應(yīng)用加入偏好設(shè)置功能
每個(gè)應(yīng)用都有個(gè)NSUserDefaults實(shí)例,通過它來存取偏好設(shè)置
比如,保存用戶名、字體大小、是否自動(dòng)登錄
下面是示例代碼
/** 保存數(shù)據(jù)*/- (IBAction)save
{
? ? // 1.利用NSUserDefaults,就能直接訪問軟件的偏好設(shè)置(Library/Preferences)是個(gè)單例對(duì)象NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
? ? //2.存儲(chǔ)數(shù)據(jù)[defaults setObject:@"sd"forKey:@"user"];//其中要保存的數(shù)據(jù)是setObject:@"sd",@“sd”是數(shù)據(jù),forKey:@"user"是以u(píng)ser的鍵值保存的,
/**
key - value
@"user" -@"sd"
*/[defaults setObject:@"123w"forKey:@"test"];
? ? [defaults setInteger:20forKey:@"age"];
? ? [defaults setBool:YES forKey:@"auto_login"];
? ? //3.立刻同步(相當(dāng)于更新數(shù)據(jù))? ? [defaults synchronize];
}/** 讀取數(shù)據(jù)*/- (IBAction)read
{
? ? //1.建立NSUserDefaults對(duì)象NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
? ? //2.讀取數(shù)據(jù)NSString *user = [defaults objectForKey:@"user"];
? ? NSString *test = [defaults objectForKey:@"test"];
? ? NSInteger age = [defaults integerForKey:@"age"];
? ? BOOL autoLogin = [defaults boolForKey:@"auto_login"];
? ? NSLog(@"user - %@\n test - %@\n age - %d\n autoLogin - %d\n,",user,test,age,autoLogin);}
//下面是解檔歸檔基本OC對(duì)象
- (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(@"解檔出來的數(shù)據(jù)是 ----- %@",testName);
}
注意:UserDefaults設(shè)置數(shù)據(jù)時(shí),不是立即寫入,而是根據(jù)時(shí)間戳定時(shí)地把緩存中的數(shù)據(jù)寫入本地磁盤。所以調(diào)用了set方法之后數(shù)據(jù)有可能還沒有寫入磁盤應(yīng)用程序就終止了。出現(xiàn)以上問題,可以通過調(diào)用synchornize方法強(qiáng)制寫入[defaults synchornize];
缺點(diǎn):本質(zhì)還是plist文件存儲(chǔ),相對(duì)于plist文件存儲(chǔ)來講存儲(chǔ)數(shù)據(jù)更快捷.
3.NSKeyedArchiver(NSCoding)
如果對(duì)象是NSString、NSDictionary、NSArray、NSData、NSNumber等類型,可以直接用NSKeyedArchiver進(jìn)行歸檔和恢復(fù)
不是所有的對(duì)象都可以直接用這種方法進(jìn)行歸檔,只有遵守了NSCoding協(xié)議的對(duì)象才可以
NSCoding協(xié)議有2個(gè)方法:
encodeWithCoder:
每次歸檔對(duì)象時(shí),都會(huì)調(diào)用這個(gè)方法。一般在這個(gè)方法里面指定如何歸檔對(duì)象中的每個(gè)實(shí)例變量,可以使用encodeObject:forKey:方法歸檔實(shí)例變量
initWithCoder:
每次從文件中恢復(fù)(解碼)對(duì)象時(shí),都會(huì)調(diào)用這個(gè)方法。一般在這個(gè)方法里面指定如何解碼文件中的數(shù)據(jù)為對(duì)象的實(shí)例變量,可以使用decodeObject:forKey方法解碼實(shí)例變量
示例代碼
1#import 2 3@interfacePerson : NSObject 4 5@property (nonatomic , copy) NSString *name; 6@property (nonatomic , assign)int age; 7@property (nonatomic , assign)double height; 8 9@end101112#import"Person.h"1314@implementation Person1516//歸檔的時(shí)候調(diào)用17/** 將某個(gè)對(duì)象寫入文件的時(shí)候會(huì)調(diào)用,在這個(gè)方法中說明哪些對(duì)象的哪些屬性需要存儲(chǔ)*/18- (void)encodeWithCoder:(NSCoder *)enCoder19{20NSLog(@"enCoder - %@",enCoder);21[enCoder encodeObject:self.name forKey:@"name"];22[enCoder encodeInt:self.age forKey:@"age"];23[enCoder encodeDouble:self.height forKey:@"height"];2425}2627/** 解檔時(shí)候調(diào)用,在這個(gè)方法中說清楚哪些屬性要解檔*/28- (id)initWithCoder:(NSCoder *)decoder29{30if(self = [super init])31? ? {32//讀取文件內(nèi)容33self.name = [decoder decodeObjectForKey:@"name"];34self.age = [decoder decodeIntForKey:@"age"];35self.height = [decoder decodeDoubleForKey:@"height"];3637? ? }3839return self;40}414243@end444546#import"SDViewController.h"47#import"Person.h"4849@interface SDViewController ()5051@end5253@implementation SDViewController5455- (void)viewDidLoad56{57? ? [super viewDidLoad];585960}6162- (IBAction)save63{64//1.數(shù)據(jù)對(duì)象65Person *p1 = [[Person alloc] init];66p1.name =@"王麻子";67p1.age =20;68p1.height =1.98;69Person *p2 = [[Person alloc] init];70p2.name =@"李四";71p2.age =56;72p2.height =1.68;73//2.歸檔數(shù)據(jù)對(duì)象74//2.1獲得文件的Documents全路徑75NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];76//2.2獲得文件的全路徑77NSString *path = [doc stringByAppendingPathComponent:@"person.txt"];78//2.3將對(duì)象歸檔79? ? [NSKeyedArchiver archiveRootObject:p1 toFile:path];8081}82- (IBAction)read83{84// 1.獲得Documents的全路徑85NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];86// 2.獲得文件的全路徑87NSString *path = [doc stringByAppendingPathComponent:@"person.txt"];88// 3.從文件中讀取Person對(duì)象89Person *p3 = [NSKeyedUnarchiver unarchiveObjectWithFile:path];9091NSLog(@"%@ %d %f", p3.name, p3.age, p3.height);9293}949596@end
NSKeyedArchiver-歸檔對(duì)象的注意:
如果父類也遵守了NSCoding協(xié)議,請(qǐng)注意:應(yīng)該在encodeWithCoder:方法中加上一句[super encodeWithCode:encode];確保繼承的實(shí)例變量也能被編碼,
即也能被歸檔應(yīng)該在initWithCoder:方法中加上一句self = [super initWithCoder:decoder];確保繼承的實(shí)例變量也能被解碼,即也能被恢復(fù)
但有時(shí)候可能想將多個(gè)對(duì)象寫入到同一個(gè)文件中,那么就要使用NSData來進(jìn)行歸檔對(duì)象NSData可以為一些數(shù)據(jù)提供臨時(shí)存儲(chǔ)空間,以便隨后寫入文件,或者存放從磁盤讀取的文件內(nèi)容。
示例代碼
? 1Person.h里面? 2? 3#import? 4? 5@interfacePerson : NSObject ? 6? 7@property (nonatomic , copy) NSString *name;? 8@property (nonatomic , assign)int age;? 9@property (nonatomic , assign)double height; 10 11@end 12 13Person.m里面 14#import"Person.h" 15 16@implementation Person 17 18//歸檔的時(shí)候調(diào)用 19/** 將某個(gè)對(duì)象寫入文件的時(shí)候會(huì)調(diào)用,在這個(gè)方法中說明哪些對(duì)象的哪些屬性需要存儲(chǔ)*/ 20- (void)encodeWithCoder:(NSCoder *)enCoder 21{ 22NSLog(@"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/** 解檔時(shí)候調(diào)用,在這個(gè)方法中說清楚哪些屬性要解檔*/ 30- (id)initWithCoder:(NSCoder *)decoder 31{ 32if(self = [super init]) 33? ? { 34//讀取文件內(nèi)容 35self.name = [decoder decodeObjectForKey:@"name"]; 36self.age = [decoder decodeIntForKey:@"age"]; 37self.height = [decoder decodeDoubleForKey:@"height"]; 38 39? ? } 40 41return self; 42} 43 44 45@end 46 47SDViewController.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.數(shù)據(jù)對(duì)象 75Person *p1 = [[Person alloc] init]; 76p1.name =@"王麻子"; 77p1.age =20; 78p1.height =1.98; 79Person *p2 = [[Person alloc] init]; 80p2.name =@"李四"; 81p2.age =56; 82p2.height =1.68; 83//2.歸檔數(shù)據(jù)對(duì)象 84//2.1獲得文件的Documents全路徑 85NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject]; 86//2.2獲得文件的全路徑 87NSString *path = [doc stringByAppendingPathComponent:@"person.txt"]; 88////2.3將對(duì)象歸檔 89//? ? [NSKeyedArchiver archiveRootObject:p1 toFile:path]; 90// 91// 新建一塊可變數(shù)據(jù)區(qū) 92NSMutableData *data = [NSMutableData data]; 93// 將數(shù)據(jù)區(qū)連接到一個(gè)NSKeyedArchiver對(duì)象 94NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; 95[archiver encodeObject:p1 forKey:@"person1"]; 96[archiver encodeObject:p2 forKey:@"person2"]; 97// 存檔完畢(一定要調(diào)用這個(gè)方法) 98? ? [archiver finishEncoding]; 99//將存檔的數(shù)據(jù)寫入文件100? ? [data writeToFile:path atomically:YES];101102}103- (IBAction)read104{105// 1.獲得Documents的全路徑106NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];107// 2.獲得文件的全路徑108NSString *path = [doc stringByAppendingPathComponent:@"person.txt"];109// 3.從文件中讀取Student對(duì)象110//? ? Person *p3 = [NSKeyedUnarchiver unarchiveObjectWithFile:path];111NSData *data = [NSData dataWithContentsOfFile:path];112113// 根據(jù)數(shù)據(jù),解析成一個(gè)NSKeyedUnarchiver對(duì)象114NSKeyedUnarchiver *unchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];115Person *p1 = [unchiver decodeObjectForKey:@"person1"];116Person *p2 = [unchiver decodeObjectForKey:@"person2"];117? ? [unchiver finishDecoding];118NSLog(@"%@ %d %f", p1.name, p1.age, p1.height);119NSLog(@"%@ %d %f", p2.name, p2.age, p2.height);120121}122123124125@end
NSCoder.h
- (void)encodeValueOfObjCType:(const?char *)type at:(const?void *)addr;?//解檔C類型數(shù)據(jù),addr傳入地址
- (void)encodeDataObject:(NSData *)data;?//歸檔一個(gè)NSData型對(duì)象
- (void)decodeValueOfObjCType:(const?char *)type at:(void *)data;?////解檔C類型數(shù)據(jù)
- (NSData *)decodeDataObject;//解檔一個(gè)NSData型對(duì)象
@end
@interface NSCoder (NSExtendedCoder)
/**?歸檔相關(guān)函數(shù)*/
- (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;
/**?解檔相關(guān)函數(shù)*/
- (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;
/**?歸檔相關(guān)函數(shù)*/
- (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;
/**?解檔相關(guān)函數(shù)*/
- (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是一款開源的嵌入式關(guān)系型數(shù)據(jù)庫,可移植性好、易使用、內(nèi)存開銷小.SQLite3是無類型的,意味著你可以保存任何類型的數(shù)據(jù)到任意表的任意字段中。
?數(shù)據(jù)庫語句
/*簡(jiǎn)單約束*/
?//如果表不存在就創(chuàng)建一張t_student的表(id為主鍵,自動(dòng)增長(zhǎng),name text類型,age integer類型);
CREATE TABLE IF NOT EXISTS t_student(id?INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER);
?//如果表不存在就創(chuàng)建一張t_student的表(id為主鍵,自動(dòng)增長(zhǎng),name text類型不能為空,age integer類型不能為空);
CREATE TABLE IF NOT EXISTS t_student(id?INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT?NULL, age INTEGER NOT?NULL);
?//如果表不存在就創(chuàng)建一張t_student的表(id為主鍵,自動(dòng)增長(zhǎng),name text類型,并且每一個(gè)是唯一的,age integer類型不能為空);
CREATE TABLE IF NOT EXISTS t_student(id?INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE, age INTEGER);
//如果表不存在就創(chuàng)建一張t_student的表(id為主鍵,自動(dòng)增長(zhǎng),name text類型,age integer類型默認(rèn)為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的數(shù)據(jù)并按照降序排列
SELECT * FROM t_student WHERE score > 50 ORDER BY age DESC;
//取出表中score<50的數(shù)據(jù)并按照升序排列,score>50的數(shù)據(jù)按照降序排列
SELECT * FROM t_student WHERE score < 50 ORDER BY age ASC , score DESC;
/*計(jì)量*/
//統(tǒng)計(jì)表中age > 50的個(gè)數(shù)
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表起個(gè)別名叫做s,利用s來引用表中的字段,取出age > 50 的數(shù)據(jù),將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;
/*修改指定數(shù)據(jù)*/
//從表中取出age = 10 的那條數(shù)據(jù),將name 字段值設(shè)為MM
UPDATE t_student SET name =?'MM'?WHERE age = 10;
/從表中取出age = 7 的那條數(shù)據(jù),將name 字段值設(shè)為WW
UPDATE t_student SET name =?'WW'?WHERE age is 7;
//取出表中age < 20 的數(shù)據(jù),并將name 全部設(shè)置為XXOO
UPDATE t_student SET name =?'XXOO'?WHERE age < 20;
//取出表中age < 50 并且 score > 10的數(shù)據(jù),將滿足條件的每一條數(shù)據(jù)中的name字段設(shè)置為NNMM
UPDATE t_student SET name =?'NNMM'?WHERE age < 50 and score > 10;
/*刪除數(shù)據(jù)*/
//刪除表中的數(shù)據(jù)
DELETE FROM t_student;
/*更新數(shù)據(jù)*/
//將表中的name字段全部設(shè)置為MM
UPDATE t_student SET name =?'MM';
/*插入數(shù)據(jù)*/
//往表中插入一條數(shù)據(jù)(name = jonathan , age = 28, score = 100)
?INSERT INTO t_student(age, score, name) VALUES ('28', 100,?'jonathan');
//往表中插入一條數(shù)據(jù)(name = lee , age = 28)
?INSERT INTO t_student(name, age) VALUES ('lee',?'28');
//往表中插入一條數(shù)據(jù)(score =? 100)
?INSERT INTO t_student(score) VALUES (100);
/*添加主鍵*/
//如果表不存在就創(chuàng)建一張表,id為主鍵自動(dòng)增長(zhǎng),integer類型,name 為text類型,age 為integer類型,score為浮點(diǎn)類型
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;
/******************************************************? 應(yīng) 用? *****************************************************************/
- (void)viewDidLoad
{
????[super?viewDidLoad];
????// 1.打開創(chuàng)建一個(gè)數(shù)據(jù)庫
????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) {
????????// 創(chuàng)建表
????????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(@"創(chuàng)建失敗");
????????}else{
????????????NSLog(@"創(chuàng)建成功");
????????}
????}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(@"創(chuàng)建失敗");
????????}else{
????????????NSLog(@"創(chuàng)建成功");
????????}
????}
}
/**
?*? 更新
?*/
- (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;
????// 查詢前的準(zhǔn)備, 檢查sql語句是否正確
????int?result = sqlite3_prepare_v2(self.db, zSql, -1, &stmt,?NULL);
????if(result == SQLITE_OK) {?// 準(zhǔn)備完成,沒有錯(cuò)誤
????????// 提取查詢到得數(shù)據(jù)到stmt, 一次提取一條
????????while(sqlite3_step(stmt) == SQLITE_ROW){
????????????// 取出提取到得記錄(數(shù)據(jù))中的第0列數(shù)據(jù)和第一列數(shù)據(jù)
????????????const?unsigned?char?*name = sqlite3_column_text(stmt, 0);
????????????int?age = sqlite3_column_int(stmt, 1);
????????????NSLog(@"%s, %d", name, age);
????????}
????}
}
SqLite3小結(jié)
1.打開數(shù)據(jù)庫
int?sqlite3_open(
????const?char?*filename,?// 數(shù)據(jù)庫的文件路徑
????sqlite3 **.ppDb?// 數(shù)據(jù)庫實(shí)例
);
2.執(zhí)行任何SQL語句
int?sqlite3_exec(
????sqlite3*,?// 一個(gè)打開的數(shù)據(jù)庫實(shí)例
????const?char?*sql,?// 需要執(zhí)行的SQL語句
????int?(*callback)(void*,int,char**,char**),?// SQL語句執(zhí)行完畢后的回調(diào)
????void?*,?// 回調(diào)函數(shù)的第1個(gè)參數(shù)
????char?**errmsg?// 錯(cuò)誤信息
);
3.檢查SQL語句的合法性(查詢前的準(zhǔn)備)
int?sqlite3_prepare_v2(
????sqlite3 *db,?// 數(shù)據(jù)庫實(shí)例
????const?char?*zSql,?// 需要檢查的SQL語句
????int?nByte,?// SQL語句的最大字節(jié)長(zhǎng)度
????sqlite3_stmt **ppStmt,?// sqlite3_stmt實(shí)例,用來獲得數(shù)據(jù)庫數(shù)據(jù)
????const?char?**pzTail
);
4.查詢一行數(shù)據(jù)
int?sqlite3_step(sqlite3_stmt*);?// 如果查詢到一行數(shù)據(jù),就會(huì)返回SQLITE_ROW
5.利用stmt獲得某一字段的值(字段的下標(biāo)從0開始)
double?sqlite3_column_double(sqlite3_stmt*,?int?iCol);?// 浮點(diǎn)數(shù)據(jù)
int?sqlite3_column_int(sqlite3_stmt*,?int?iCol);?// 整型數(shù)據(jù)
sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*,?int?iCol);?// 長(zhǎng)整型數(shù)據(jù)
const?void?*sqlite3_column_blob(sqlite3_stmt*,?int?iCol);?// 二進(jìn)制文本數(shù)據(jù)
const?unsigned?char?*sqlite3_column_text(sqlite3_stmt*,?int?iCol);?// 字符串?dāng)?shù)據(jù)
6.SqLite3第三方框架FMDB使用小結(jié)
?FMDB是iOS平臺(tái)的SQLite數(shù)據(jù)庫框架,FMDB以O(shè)C的方式封裝了SQLite的C語言API.
FMDB的優(yōu)點(diǎn)
@1使用起來更加面向?qū)ο?,省去了很多麻煩、冗余的C語言代碼
@2對(duì)比蘋果自帶的Core Data框架,更加輕量級(jí)和靈活
@3提供了多線程安全的數(shù)據(jù)庫操作方法,有效地防止數(shù)據(jù)混亂
?FMDB簡(jiǎn)單使用示例代碼
#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.獲得數(shù)據(jù)庫對(duì)象self.db = [FMDatabase databaseWithPath:fileName];
? ? // 2.打開數(shù)據(jù)庫if ([self.db open]) {
? ? ? ? NSLog(@"打開成功");
? ? ? ? // 2.1創(chuàng)建表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(@"創(chuàng)建表成功");
? ? ? ? }else? ? ? ? {
? ? ? ? ? ? NSLog(@"創(chuàng)建表失敗");
? ? ? ? }
? ? }else? ? {
? ? ? ? NSLog(@"打開失敗");
? ? }
}- (IBAction)insertBtnClick
{
? ? for(inti =0; i <100; i++) {
? ? ? ? NSString *name = [NSString stringWithFormat:@"Jonathan-%d", i];
? ? ? ? intage = arc4random_uniform(1000);
? ? ? ? BOOL success = [self.db executeUpdate:@"INSERT INTO t_student(name , age) VALUES(?, ?);", name, @(age)];// 注意只能拼接對(duì)象類型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.取出數(shù)據(jù)while([set next]) {
? ? ? ? // 取出姓名//? ? ? NSString *name = [set stringForColumnIndex:1];
? ? ? ? // 取出年齡//? ? ? int age = [set intForColumnIndex:2];NSString *name = [setstringForColumn:@"name"];
? ? ? ? intage = [setintForColumn:@"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.獲得數(shù)據(jù)庫對(duì)象//? ? self.db = [FMDatabase databaseWithPath:fileName];
? ? // 1.活的數(shù)據(jù)庫隊(duì)列對(duì)象self.queue = [FMDatabaseQueue databaseQueueWithPath:fileName];
? ? // 2.在數(shù)據(jù)庫隊(duì)列中執(zhí)行線程安全的操作[self.queue inDatabase:^(FMDatabase *db) {
? ? ? ? if ([db open]) {
? ? ? ? ? ? // 2.1創(chuàng)建表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(@"創(chuàng)建表成功");
? ? ? ? ? ? }else? ? ? ? ? ? {
? ? ? ? ? ? ? ? NSLog(@"創(chuàng)建表失敗");
? ? ? ? ? ? }
? ? ? ? }
? ? }];
}- (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]; // 開啟事務(wù)
? ? ? ? [db executeUpdate:@"update t_person set money = 0 where name = 'Zs';"];
//? ? ? ? [db rollback];// 主動(dòng)回滾
? ? ? ? [db executeUpdate:@"update t_person set money = 2000 where name = 'LS';"];
? ? ? ? [db commit];// 提交事務(wù)
? ? }];
? ? */? ?
? ? [self.queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
? ? ? ? [db executeUpdate:@"update t_person set money = 0 where name = 'Zs';"];
? ? ? ? NSLog(@"主動(dòng)回滾");
? ? ? ? *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.取出數(shù)據(jù)while([set next]) {
? ? ? ? ? ? NSString *name = [setstringForColumn:@"name"];
? ? ? ? ? ? intage = [setintForColumn:@"age"];
? ? ? ? ? ? NSLog(@"name = %@, age = %d", name, age);
? ? ? ? }
? ? }];
}@end