緩存分為:內(nèi)存緩存 和 數(shù)據(jù)持久化(磁盤緩存)
內(nèi)存緩存:
內(nèi)存緩存是指當(dāng)前程序運(yùn)行空間聚蝶,內(nèi)存緩存速度快容量小,它是供cpu直接讀取街氢,
比如我們打開一個(gè)程序漫雷,他是運(yùn)行在內(nèi)存中的,關(guān)閉程序后內(nèi)存又會(huì)釋放习蓬。
常用框架:NSCache, YYMemoryCache.
我們常說的分區(qū)(從高地址到低地址):棧區(qū)纽什,堆區(qū), 全局區(qū)友雳, 常量區(qū)稿湿, 代碼區(qū)铅匹。 就是內(nèi)存的范疇押赊。
所以內(nèi)存緩存指的就是將數(shù)據(jù)存儲(chǔ)到這些區(qū)域。 一般是將數(shù)據(jù)緩存到堆區(qū)包斑。
頻繁的從磁盤中讀取數(shù)據(jù)是比較耗性能的流礁。 所以一般是先從磁盤中取到數(shù)據(jù),存到內(nèi)存緩存中罗丰,以達(dá)到性能優(yōu)化神帅。
磁盤緩存
就是 數(shù)據(jù)持久化。?
就是將數(shù)據(jù)保存到硬盤中(沙盒中)萌抵,使得在應(yīng)用程序或機(jī)器重啟后可以繼續(xù)訪問之前保存的數(shù)據(jù)找御。
沙盒的結(jié)構(gòu)
沙盒的路徑
NSHomeDirectory();
1元镀、Documents
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
2、Library
2.1 Caches
NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
2.2 Preference
這個(gè)文件夾里存的是 通過NSUserDefault 方式存儲(chǔ)的plist文件
//獲取Preferences目錄. 通常情況下霎桅,Preferences有系統(tǒng)維護(hù)栖疑,所以我們很少去操作它。
NSString *preferPath = [LibraryPath stringByAppendingPathComponent:@"Preferences"];
3滔驶、tmp
NSString *path = NSTemporaryDirectory();
緩存存放路徑的規(guī)定:
用戶生成的文件放在documents遇革,自己的文件放在library/cache里面。
如果你做個(gè)記事本的app揭糕,那么用戶寫了東西萝快,總要把東西存起來。那么這個(gè)文件則是用戶自行生成著角,就放在documents文件夾里面揪漩。
如果你有一個(gè)app,需要和服務(wù)器配合雇寇,經(jīng)常從服務(wù)器下載東西氢拥,展示給用戶看。那么這些下載下來的東西就放在library/cache锨侯。
使用**Xcode**獲取沙盒文件**(**模擬器和真機(jī)**)** 查看沙盒內(nèi)容
[https://blog.csdn.net/wangxiaopeng1103/article/details/52947521](https://blog.csdn.net/wangxiaopeng1103/article/details/52947521)
數(shù)據(jù)持久化存儲(chǔ)的幾種方式:
[https://blog.csdn.net/jiankeufo/article/details/79347330](https://blog.csdn.net/jiankeufo/article/details/79347330)
**1.plist**文件
這個(gè)方法可以指定存儲(chǔ)在沙盒的路徑嫩海。
writeToFile方法。?
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *fileName = [path stringByAppendingPathComponent:@"123.plist"];
NSArray *array = @[@"123", @"456", @"789"];
[array writeToFile:fileName atomically:YES];
NSArray *result = [NSArray arrayWithContentsOfFile:fileName];
NSLog(@"%@", result);
**2.**偏好設(shè)置**preference**
在沙盒的preference目錄下的一個(gè)以此應(yīng)用包名來命名的plist文件囚痴。
NSUserDefaults存儲(chǔ)不可變類型數(shù)據(jù)
//1.獲得NSUserDefaults
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
//2.向文件中寫入內(nèi)容
[userDefaults setObject:@"AAA" forKey:@"a"];
[userDefaults setBool:YES forKey:@"sex"];
[userDefaults setInteger:21 forKey:@"age"];
//2.1立即同步
[userDefaults synchronize];
//3.讀取文件
NSString *name = [userDefaults objectForKey:@"a"];
BOOL sex = [userDefaults boolForKey:@"sex"];
NSInteger age = [userDefaults integerForKey:@"age"];
NSLog(@"%@, %d, %ld", name, sex, age);
**3.**歸檔**NSKeyedArchiver** 解檔**NSKeyedUnarchiver**
遵循NSCoding
存儲(chǔ)的是 .data文件
//1.遵循NSCoding協(xié)議?
@interface Person : NSObject <NSCoding>
//2.設(shè)置屬性
@property (strong, nonatomic) UIImage *avatar;
@property (copy, nonatomic) NSString *name;
@property (assign, nonatomic) NSInteger age;
@end
//實(shí)現(xiàn)協(xié)議的兩個(gè)方法
//解檔
- (id)initWithCoder:(NSCoder *)aDecoder {
if ([super init]) {
self.avatar = [aDecoder decodeObjectForKey:@"avatar"];
self.name = [aDecoder decodeObjectForKey:@"name"];
self.age = [aDecoder decodeIntegerForKey:@"age"];
}
return self;
}
//歸檔
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.avatar forKey:@"avatar"];
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeInteger:self.age forKey:@"age"];
}
使用:
NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.data"];
Person *person = [[Person alloc] init];
person.avatar = self.avatarView.image;
person.name = self.nameField.text;
person.age = [self.ageField.text integerValue];
//寫入person.data文件 ? ?
[NSKeyedArchiver archiveRootObject:person toFile:file];
NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.data"];
//根據(jù)person.data文件讀取數(shù)據(jù) ? ?
Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:file];
if (person) {
self.avatarView.image = person.avatar;
self.nameField.text = person.name;
self.ageField.text = [NSString stringWithFormat:@"%ld", person.age];
}
FMDB
[https://www.cnblogs.com/Yun-Longcom/p/6008724.html](https://www.cnblogs.com/Yun-Longcom/p/6008724.html)
SQL語法
[https://blog.csdn.net/m0_37177053/article/details/78350202](https://blog.csdn.net/m0_37177053/article/details/78350202)
FMDatabase : 一個(gè)單一的SQLite數(shù)據(jù)庫叁怪,用于執(zhí)行SQL語句。
FMResultSet :執(zhí)行查詢一個(gè)FMDatabase結(jié)果集深滚。
FMDatabaseQueue :在多個(gè)線程來執(zhí)行查詢和更新時(shí)會(huì)使用這個(gè)類
首先創(chuàng)建數(shù)據(jù)庫:
NSString *path=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
path=[path stringByAppendingPathComponent:@"test.sqlite"];
FMDatabase *dataBase= [FMDatabase databaseWithPath:path]; //數(shù)據(jù)庫有數(shù)據(jù)庫的名稱 test.sqlite
創(chuàng)建表:
NSString * create1=@"create table if not exists t_user(id integer autoincrement primary key,name varchar)";?
**BOOL c1= [dataBase executeUpdate:create1]; //**表有表的名稱 **t_user**
插入數(shù)據(jù)
**NSString * insertSql = @"insert into t_user(id,name) values(?,?)";**
bool inflag1 = [dataBase executeUpdate:insertSql,@(2),@"admin"];
if(inflag1){
NSLog(@“增加成功");
}
刪除語句
**NSString * delete=@"delete from t_user";**
BOOL dflag= [dataBase executeUpdate:delete];
if(dflag){
NSLog(@"刪除成功");
}
修改語句
**NSString *update=@" update t_user set name=? ";**
BOOL flag= [dataBase executeUpdate:update,@"zhangsan"];
if(flag){
NSLog(@"修改成功");
}
查詢語句
**NSString * sql=@" select * from t_user ";**
**FMResultSet *result=[dataBase executeQuery:sql];**
while(result.next){
int ids=[result intForColumn:@"id"];
NSString * name=[result stringForColumn:@"name"];
int ids=[result intForColumnIndex:0];
NSString * name=[result stringForColumnIndex:1];
NSLog(@"%@,%d",name, ids);? ? ?
}
注意:
創(chuàng)建表奕谭,增,刪痴荐,改 都使用executeUpdate方法
- (BOOL)executeUpdate:(NSString*)sql, ...
- (BOOL)executeUpdateWithFormat:(NSString*)format, ...
- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments
只有查詢使用executeQuery方法
- (FMResultSet *)executeQuery:(NSString*)sql, ...
- (FMResultSet *)executeQueryWithFormat:(NSString*)format, ...
- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments
多線程的操作
如果應(yīng)用中使用了多線程操作數(shù)據(jù)庫血柳,那么就需要使用FMDatabaseQueue來保證線程安全了。?
應(yīng)用中不可在多個(gè)線程中共同使用一個(gè)FMDatabase對(duì)象操作數(shù)據(jù)庫生兆,這樣會(huì)引起數(shù)據(jù)庫數(shù)據(jù)混亂难捌。?
為了多線程操作數(shù)據(jù)庫安全,F(xiàn)MDB使用了FMDatabaseQueue鸦难。
使用FMDatabaseQueue很簡單根吁,首先用一個(gè)數(shù)據(jù)庫文件地址來初使化FMDatabaseQueue,然后就可以將一個(gè)閉包(block)傳入inDatabase方法中合蔽。 在閉包中操作數(shù)據(jù)庫击敌,而不直接參與FMDatabase的管理
NSString *path=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
path=[path stringByAppendingPathComponent:@"test.sqlite"];
//創(chuàng)建一個(gè)test.sqlite數(shù)據(jù)庫
FMDatabaseQueue *queue=[FMDatabaseQueue databaseQueueWithPath:path];?
[queue inDatabase:^(FMDatabase *db) {
//創(chuàng)建一個(gè)t_book表。
NSString * create=@"create table if not exists t_book(id integer,name varchar)";
BOOL c1= [db executeUpdate:create];
if(c1){
NSLog(@"成功");
}
}];
[queue inDatabase:^(FMDatabase *db) {
NSString * insertSql=@"insert into t_book(id,name) values(?,?)";
//插入語句1
bool inflag=[db executeUpdate:insertSql,@(2),@"admin"];
if(inflag){
NSLog(@"插入成功");
}
}];
[queue inDatabase:^(FMDatabase *db) {
//查詢語句1
FMResultSet *data = [db executeQuery:@" select * from t_book "];
while (data.next) {
int ids=[data intForColumn:@"id"];
NSString *name=[data stringForColumn:@"name"];
NSLog(@"%@",name);
NSLog(@"%i",ids);? ?
}
}];