簡(jiǎn)述
數(shù)據(jù)儲(chǔ)存可以分為數(shù)據(jù)結(jié)構(gòu)和儲(chǔ)存方式闷串。數(shù)據(jù)結(jié)構(gòu)就是數(shù)據(jù)存在的的形式。例如 NSDictionnary衡蚂、NSArray窿克、NSSet等這些簡(jiǎn)單的對(duì)象,也有像CoreData那樣的關(guān)系模型毛甲。儲(chǔ)存方式在機(jī)器內(nèi)則分為兩種:1年叮、內(nèi)存;2玻募、閃存只损。內(nèi)存存儲(chǔ)是臨時(shí)的,但是運(yùn)行速率非称哌郑快跃惫,閃存則是一種持久化存儲(chǔ),效率非常低艾栋。我們常說(shuō)的歸檔就是將內(nèi)存中的數(shù)據(jù)轉(zhuǎn)移到閃存就行持久化保存爆存。我們只有把內(nèi)存和閃存結(jié)合起來(lái)進(jìn)行操作才算完整的數(shù)據(jù)儲(chǔ)存方案。盜圖來(lái)說(shuō)明:
常見(jiàn)方式
iOS中常用的有:SQLite蝗砾、CoreData先较、Plist、NSUserDefault悼粮。
- NSUserDefault: 用于儲(chǔ)存配置信息
- SQLite: 主要用來(lái)儲(chǔ)存數(shù)量較多的小型數(shù)據(jù)
- CoreData: 類似SQLite闲勺,但沒(méi)SQLite那么靈活
- Plist: 用于存儲(chǔ)圖像、音頻等大體積數(shù)據(jù)
NSUserDefault
常規(guī)儲(chǔ)存
NSUserDefault可以看做為APP的一個(gè)全局單例扣猫,整個(gè)APP中只有一個(gè)實(shí)例對(duì)象菜循,可以用于永久保存數(shù)據(jù),非常容易操作申尤。它支持儲(chǔ)存的數(shù)據(jù)類型有:NSNumber癌幕、NSString、NSDictionary昧穿、NSArray序芦、NSDate、BOOL粤咪。他的數(shù)據(jù)存儲(chǔ)是通過(guò)key--value一一對(duì)應(yīng)的(key必須唯一);存儲(chǔ)自定義對(duì)象
儲(chǔ)存小數(shù)量的自定義數(shù)據(jù)可以用NSUserDefault谚中,但是這個(gè)自定義數(shù)據(jù)必須實(shí)現(xiàn)歸檔協(xié)議,不然會(huì)存不進(jìn)去,只有轉(zhuǎn)化成NSData類型才能通過(guò)NSUserDefault儲(chǔ)存宪塔,如果是多個(gè)自定義數(shù)據(jù)可以添加到數(shù)組中磁奖,然后歸檔存儲(chǔ)到NSUserDefault中。
歸檔 解檔
//歸檔
-(void)encodeWithCoder:(NSCoder *)aCoder{
unsigned int count;
objc_property_t *properties = class_copyPropertyList([self class], &count);
for (int i = 0; i < count; i++) {
const char * propertyCsString = property_getName(properties[i]);
NSString * propertyName = [NSString stringWithCString:propertyCsString encoding:NSUTF8StringEncoding];
id propertyValue = [self valueForKey:propertyName];
[aCoder encodeObject:propertyValue forKey:propertyName];
}
free(properties);
}
//解檔
-(instancetype)initWithCoder:(NSCoder *)aDecoder{
self = [super init];
if (self) {
unsigned int count;
objc_property_t *properties = class_copyPropertyList([self class], &count);
for (int i = 0; i < count; i++) {
const char *property_csNam = property_getName(properties[i]);
NSString *p_key = [NSString stringWithCString:property_csNam encoding:NSUTF8StringEncoding];
id value = [aDecoder decodeObjectForKey:p_key];
[self setValue:value forKey:p_key];
}
free(properties);
}
return self
}
///copy 協(xié)議
-(id)copyWithZone:(NSZone *)zone{
StudentModel *s_model = [[self copyWithZone:zone] init];
unsigned int count;
objc_property_t *properties = class_copyPropertyList([self class], &count);
for (int i = 0; i < count; i++) {
const char *propertyCS = property_getName(properties[i]);
NSString *p_key = [NSString stringWithCString:propertyCS encoding:NSUTF8StringEncoding];
id p_value = [self valueForKey:p_key];
[s_model setValue:p_value forKey:p_key];
}
free(properties);
return s_model;
}
//存儲(chǔ)自定義對(duì)象
StudentModel *s_model = [[StudentModel alloc] init];
s_model.s_name = @"xiaoqiang";
s_model.s_id = @"22";
s_model.s_password = @"123456";
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:s_model];
[u_default setObject:data forKey:@"s_student"];
[u_default synchronize];
NSData *rachiverData = [u_default objectForKey:@"s_student"];
StudentModel *model = [NSKeyedUnarchiver unarchiveObjectWithData:rachiverData];
NSLog(@"\n name is %@ \n id is %@ \n password is %@",model.s_name,model.s_id,model.s_password);
Plist
沙盒
機(jī)制:
iOS沙盒機(jī)制就是指該APP只能訪問(wèn)自己的沙盒目錄下的文件某筐,不能訪問(wèn)其他APP的沙盒文件比搭,主要用來(lái)保存圖像、圖標(biāo)南誊、聲音身诺、屬性列表,文本等抄囚,不過(guò)iOS 8后新開(kāi)放了幾個(gè)固定系統(tǒng)區(qū)域的擴(kuò)展機(jī)制extension霉赡,它可以一定程度上解決APP之間的通信限制。
目錄
Documents
Documents主要用來(lái)保存APP運(yùn)行時(shí)需要持久化保存的數(shù)據(jù)幔托,該目錄會(huì)被iTunes同步時(shí)備份-
Library
2.1 . Caches
Caches是用來(lái)保存APP運(yùn)行時(shí)需要持久化儲(chǔ)存的數(shù)據(jù)穴亏,但不會(huì)被iTunes同步,所以該目錄適合保存一些體積大而且不需要備份的數(shù)據(jù)2.2. Prefrernces
PreFrernces是用來(lái)保存應(yīng)用偏好設(shè)置的重挑,iOS的設(shè)置應(yīng)用會(huì)在該目錄中查找應(yīng)用設(shè)置的信息嗓化,也會(huì)被iTunes同步到備份 tmp
保存APP運(yùn)行時(shí)的臨時(shí)數(shù)據(jù),關(guān)閉APP后會(huì)被自動(dòng)刪除
獲取目錄方式
拼接獲让А:
NSString *homePath = NSHomeDirectory();
NSString *path = [homePath stringByAppendingPathComponent:@"Documents"];
return [path stringByAppendingPathComponent:suffix]; `
打印得到的路徑:/var/mobile/Containers/Data/Application/0FB7706E-625C-482C-B1DE-DDD241BB3220/Documents/test.plist
利用NSSearchPathForDirectoriesInDomains函數(shù)獲得Documents目錄:
NSArray *pathArr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = pathArr[0];
return [path stringByAppendingPathComponent:suffix];
打印得到的路徑:` /var/mobile/Containers/Data/Application/0FB7706E-625C-482C-B1DE-DDD241BB3220/Documents/test.plist
第一個(gè)參數(shù)為代表文件路徑 一般用到NSDocumentDirectory或者NSCachesDirectory 第二個(gè)參數(shù)一般為NSUserDomainMask刺覆,第三個(gè)參數(shù)代表是否打開(kāi)一般為YES,上面PathArr 一般只能或得一個(gè)元素史煎,
補(bǔ)充
獲取沙盒tmp目錄的方法:
NSString *tmp = NSTemporaryDirectory();
獲取沙盒caches目錄方法:
NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
獲取應(yīng)用沙盒preference目錄的方法:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
言歸正傳繼續(xù)plist操作筆記 plist儲(chǔ)存的數(shù)據(jù):array,dictionary,string,bool,date,data這幾種類型隅津,如果要存儲(chǔ)自定義的也要實(shí)現(xiàn)歸檔協(xié)議然后轉(zhuǎn)換成NSData類型儲(chǔ)存,plist主要用來(lái)存儲(chǔ)大文件劲室。
NSString *path = [self getPlistLibraryWithSuffix:@"test.plist"];
NSMutableArray *stu_array = [NSMutableArray new];
for (int i = 0; i < 10; i ++) {
StudentModel *s_model = [StudentModel new];
s_model.s_name = [NSString stringWithFormat:@"name%d",i];
s_model.s_id = [NSString stringWithFormat:@"%d",100 + i];
s_model.s_password = @"123456";
[stu_array addObject:s_model];
}
///寫(xiě)入
NSData *archiverData = [NSKeyedArchiver archivedDataWithRootObject:stu_array];
BOOL isSuc = [archiverData writeToFile:path atomically:YES];
// BOOL isSuc = [NSKeyedArchiver archiveRootObject:stu_array toFile:path];
NSLog(@"%d",isSuc);
///讀取
NSData *unarchiverData = [NSData dataWithContentsOfFile:path];
NSArray *unArchiverArr = [NSKeyedUnarchiver unarchiveObjectWithData:unarchiverData];
// NSArray *unArchiverArr = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
NSLog(@"%@==",unArchiverArr);
SQLite:
iOS的SDK有SQLite的庫(kù),我們可以自建SQLite數(shù)據(jù)庫(kù)结窘,SQLite每次寫(xiě)入數(shù)據(jù)都會(huì)產(chǎn)生IO消耗很洋,把數(shù)據(jù)歸檔到相應(yīng)的文件。其實(shí)SQLite也跟NSUserDefaults差不多隧枫,適合儲(chǔ)存基礎(chǔ)類型的小數(shù)據(jù)喉磁,不過(guò)它更適合存儲(chǔ)大量的數(shù)據(jù),類似聊天記錄這樣的數(shù)據(jù)查詢和儲(chǔ)存官脓。SQLite的操作比較復(fù)雜协怒,因?yàn)樗皇敲嫦驅(qū)ο蟮模覀冇闷饋?lái)很不習(xí)慣卑笨,但是我們可以用第三發(fā)框架FMDB孕暇,在工程中pod FMDB 進(jìn)來(lái)。
FMDB:
- FMDataBase:它主要用來(lái)執(zhí)行SQL語(yǔ)句,但是它線程不安全的
- FMResult 用于查詢結(jié)果
- FMDatabaseQueue 多余多線程查詢或者更新 它是線程安全的
FMDB幾個(gè)主要的方法
FMDB中除了查詢之外都可以稱作為更新妖滔,create隧哮、delete,update座舍、insert沮翔、drop,使用executeUpdate:方法更新
更新
- (BOOL)executeUpdate:(NSString*)sql, ...
- (BOOL)executeUpdateWithFormat:(NSString*)format, ...
- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments
- (BOOL)executeUpdate:(NSString*)sql withParameterDictionary:(NSDictionary *)arguments;
查詢
- (FMResultSet *)executeQuery:(NSString*)sql, ...
- (FMResultSet *)executeQueryWithFormat:(NSString*)format, ...
- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments
SQL語(yǔ)句
- 創(chuàng)建表語(yǔ)句
create table if not exists StudentTab(numberID integer primary key not NULL ,name text,headImage blob,scroll real)
這表示如果不存在StudentTab曲秉,則創(chuàng)建一個(gè)NumberID自動(dòng)增加的的序號(hào)值采蚀,name是文本字符串類型,head為二進(jìn)制類型承二,scroll為浮點(diǎn)型類型
- 插入語(yǔ)句
insert into Student(name,headImage,scroll) values (?,?,?)
insert into Student values (:name,:headImage,:scorll)榆鼠;
insert into Student(name,headImage,scroll) values('%@','%@','%lf')
//這三句等價(jià)
- 更新語(yǔ)句
update Student set name = ? where scoll = ?
- 刪除語(yǔ)句
delete from Student where name = ?
drop table if exists Student
- 查詢語(yǔ)句
select * from Student where name = ?
特殊用法:
如果你要保存的參數(shù)個(gè)數(shù)未知或者數(shù)量較多 我們可以用一下這些方法 給讓你感受到很好的體驗(yàn)
- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments
- (BOOL)executeUpdate:(NSString*)sql withParameterDictionary:(NSDictionary *)arguments;
數(shù)據(jù)庫(kù)的事務(wù)也很好用 inDeferredTransaction
CoreData
- NSManagedObjectModel(被管理的對(duì)象模型)相當(dāng)于實(shí)體矢洲,但它也包含了實(shí)體間的關(guān)系璧眠,
- NSManagedObjectContext(被管理的對(duì)象上下文)操作的作用有:插入數(shù)據(jù)、查詢读虏、更新责静、刪除
- NSPersistentStoreCoordinator(持久化儲(chǔ)存助理)它充當(dāng)這與數(shù)據(jù)庫(kù)連接的角色
- NSPredicate(相當(dāng)于查詢條件)
- NSFetchRequest(獲取數(shù)據(jù)的請(qǐng)求)
- NSEntityDescription(實(shí)體結(jié)構(gòu))
- NSFetchedResultsController:監(jiān)聽(tīng)數(shù)據(jù)變化 實(shí)現(xiàn)代理 當(dāng)數(shù)據(jù)發(fā)生變化會(huì)盡代理
NSFetchRequest *result = [NSFetchRequest fetchRequestWithEntityName:@"User"];`
NSSortDescriptor * desciptor = [NSSortDescriptor sortDescriptorWithKey:@"u_name" ascending:YES];
[result setSortDescriptors:@[desciptor]];
NSManagedObjectContext *context = self.manager.mainManagedObjectContext;
self.userFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:result managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
self.userFetchedResultsController.delegate = self;
版本遷移
coredata需要注意版本更新數(shù)據(jù)遷移處理 一般加自動(dòng)遷移處理
//自動(dòng)遷移
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
abort();
}
return _persistentStoreCoordinator;
}
插入
User *user = (User *)[NSEntityDescription insertNewObjectForEntityForName:@"User" inManagedObjectContext:self.manager.mainManagedObjectContext];
[user setU_age:@"26"];
[user setU_name:@"liu"];
[user setU_sex:@"1"];
NSError *error ;
BOOL isSuc =[self.manager.mainManagedObjectContext save:&error];
刪除
NSFetchRequest *result = [[NSFetchRequest alloc] init];
NSEntityDescription *user = [NSEntityDescription entityForName:@"User" inManagedObjectContext:self.manager.mainManagedObjectContext];
[result setEntity:user];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"u_name = %@",@"liu"];
[result setPredicate:predicate];
NSError *error = nil;
NSArray *arr = [self.manager.mainManagedObjectContext executeFetchRequest:result error:&error];
if (arr.count == 0) {
NSLog(@"error is %@",error);
}else{
for (User *temp in arr) {
[self.manager.mainManagedObjectContext deleteObject:temp];
}
}
[self.manager.mainManagedObjectContext saveAndWait:YES error:&error];
更新:
NSFetchRequest *result = [[NSFetchRequest alloc] init];
NSEntityDescription *user = [NSEntityDescription entityForName:@"User" inManagedObjectContext:self.manager.mainManagedObjectContext];
[result setEntity:user];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"u_name = %@",@"liu"];
[result setPredicate:predicate];
NSError *erro = nil;
NSArray *arr = [self.manager.mainManagedObjectContext executeFetchRequest:result error:&erro];
if (arr.count == 0) {
NSLog(@"%@ error ",erro);
}else{
for (User *tempUser in arr) {
tempUser.u_age = @"18";
}
}
[self.manager.mainManagedObjectContext save:&erro];
查詢
NSFetchRequest *result = [[NSFetchRequest alloc] init];
NSEntityDescription *user = [NSEntityDescription entityForName:@"User" inManagedObjectContext:self.manager.mainManagedObjectContext];
[result setEntity:user];
NSError *error ;
NSMutableArray *arr = [[self.manager.mainManagedObjectContext executeFetchRequest:result error:&error] mutableCopy];
if (arr.count == 0) {
NSLog(@"error is %@",error);
}
else{
for (User *tempUser in arr) {
NSLog(@"%@==%@===%@",tempUser.u_name,tempUser.u_age,tempUser.u_sex);
}
}
線程安全處理
+(id) instanceChildManagedObjectContext {
NSManagedObjectContext *context = nil;
if ([NSThread isMainThread]) {
context = [[CoreDataManager sharedCoreDataManager] mainManagedObjectContext];
} else {
context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
context.parentContext = [[CoreDataManager sharedCoreDataManager] mainManagedObjectContext];
}
return context;
}