IOS 數(shù)據(jù)持久化

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容