iOS開發中本地存儲主要有三種形式
應用沙盒
要想在本地存儲數據,那就要知道一下什麼是應用沙盒 ,其實很好理解應用沙盒就是應用的文件夾,與其餘文件系統隔離。每個iOS應用都有本身的應用沙盒,應用必須待在本身的沙盒裏,其它應用不能訪問該沙盒。
如何獲取應用沙盒路徑,能夠經過打印NSHomeDirectory()來獲取應用沙盒路徑,下圖爲打印路徑結果:html
Melody_Zhy 是用戶文件夾(樣子是個小房子)
3CEC8EEB-C230-44BE-93B7-DF3B9A120A94 iOS8以後每次運行Xcode都會生成不一樣的沙盒路徑,不一樣之處就是最後這個文件夾名,多是蘋果爲了安全着想android
首先咱們先來看下,應用沙盒裏面都有什麼ios
這裏提一下Finder的快捷鍵 shift + com + g 能夠前往任意路徑的文件夾,所以咱們能夠打印沙盒路徑以後將沙盒路徑複製到Finder前往路徑文件夾中,前往應用沙盒。這是一個比較耽誤事的方法!幸虧有一款叫作simpholders的app,它能夠很簡單的訪問應用的沙盒路徑,記得去下載simpholders2哦,第一代iOS8以後就不能用了,app很簡單易懂,用下就會了~
如今咱們來看看應用沙盒裏面這些文件夾都是作什麼用的git
應用沙盒目錄的常見獲取方式
正如上面咱們所說:github
NSString *home = NSHomeDirectory();
第一種( !笨!)sql
// 利用沙盒根目錄拼接字符串 NSString *homePath = NSHomeDirectory(); NSString *docPath = [homePath stringByAppendingString:@"/Documents"];
第二種( !還👌!)數據庫
// 利用沙盒根目錄拼接」Documents」字符串 NSString *homePath = NSHomeDirectory(); NSString *docPath = [homePath stringByAppendingPathComponent:@"Documents"];
可是不建議使用這種方法,由於不定哪天蘋果大大就把文件名稱改了呢-_-!編程
第三種( !~推薦~ !)數組
// NSDocumentDirectory 要查找的文件 // NSUserDomainMask 表明從用戶文件夾下找 // 在iOS中,只有一個目錄跟傳入的參數匹配,因此這個集合裏面只有一個元素 NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; NSString *filePath = [path stringByAppendingPathComponent:@"xxx.plist"];
這裏我來詳細的說下NSSearchPathForDirectoriesInDomains這個方法的幾個參數 :
<#NSSearchPathDirectory directory#> 這個參數表明要查找的文件,是個枚舉! 枚舉你懂的點擊去看看就知道了~
<#NSSearchPathDomainMask domainMask#> 這個參數表明從用戶文件夾下找,也是枚舉!
最後一個參數若是是NO的話,打印的路徑會是這種形式~/Documents,咱們通常都會用YES,這樣能夠獲取完整路徑字符串!
這個方法的返回值是一個數組,但在iOS中,只有一個目錄跟傳入的參數匹配,因此這個集合裏面只有一個元素,因此咱們取第一個元素!緩存
這裏我只用上面的第三種方法!注意第一個參數!
NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]; NSString *filePath = [path stringByAppendingPathComponent:@"student.data"];
NSString *tmp= NSTemporaryDirectory();
經過NSUserDefaults類存取該目錄下的設置信息!
!!!這個下面會有介紹!!!
XML屬性列表(plist)歸檔
plist的根Type只能是字典(NSDictionary)或者是數組(NSArray)因此歸檔時咱們只能將數組或字典保存到plist文件中,可是NSString也能經過歸檔保存到plist文件中同時它也能夠經過stringWithContentsOfFile解檔,它保存到plist中時Type是空的,Value是有值的!
NSArray *arr = [[NSArray alloc] initWithObjects:@"1", @"2", nil]; // NSDocumentDirectory 要查找的文件 // NSUserDomainMask 表明從用戶文件夾下找 // 在iOS中,只有一個目錄跟傳入的參數匹配,因此這個集合裏面只有一個元素 NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; NSString *filePath = [path stringByAppendingPathComponent:@"xxx.plist"]; [arr writeToFile:filePath atomically:YES];
NSString *filePath = [path stringByAppendingPathComponent:@"xxx.plist"]; // 解檔 NSArray *arr = [NSArray arrayWithContentsOfFile:filePath]; NSLog(@"%@", arr);
Preference(偏好設置)
OC中有一個NSUserDefaults的單例,它能夠用來存儲用戶的偏好設置,例如:用戶名,字體的大小,用戶的一些設置等,下面我用兩個UISwitch來演示如何保存用戶設置開關的關閉狀態
// 獲取用戶偏好設置對象 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; // 保存用戶偏好設置 [defaults setBool:self.one.isOn forKey:@"one"]; [defaults setBool:self.two.isOn forKey:@"two"]; // 注意:UserDefaults設置數據時,不是當即寫入,而是根據時間戳定時地把緩存中的數據寫入本地磁盤。因此調用了set方法以後數據有可能尚未寫入磁盤應用程序就終止了。 // 出現以上問題,能夠經過調用synchornize方法強制寫入 // 如今這個版本不用寫也會立刻寫入 不過以前的版本不會 [defaults synchronize];
// 讀取用戶偏好設置 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; self.one.on = [defaults boolForKey:@"one"]; self.two.on = [defaults boolForKey:@"two"];
NSKeyedArchiver歸檔(NSCoding)
只有遵照了NSCoding協議的類才能夠用NSKeyedArchiver歸檔和NSKeyedUnarchiver解檔,若是對象是NSString、NSDictionary、NSArray、NSData、NSNumber等類型,能夠直接用NSKeyedArchiver歸檔和NSKeyedUnarchiver解檔~
下面我舉的🌰是歸檔解檔一個Student模型,所以該模型應該遵照NSCoding協議
- (void)encodeWithCoder:(NSCoder *)coder { [coder encodeObject:self.name forKey:@"name"]; [coder encodeInteger:self.age forKey:@"age"]; } - (instancetype)initWithCoder:(NSCoder *)coder { self = [super init]; if (self) { self.age = [coder decodeIntegerForKey:@"age"]; self.name = [coder decodeObjectForKey:@"name"]; } return self; }
Student *s1 = [[Student alloc] init];
s1.name = @"zzz"; s1.age = 18; NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]; // 這個文件後綴能夠是任意的,只要不與經常使用文件的後綴重複便可,我喜歡用data NSString *filePath = [path stringByAppendingPathComponent:@"student.data"]; // 歸檔 [NSKeyedArchiver archiveRootObject:s1 toFile:filePath];
NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]; NSString *filePath = [path stringByAppendingPathComponent:@"student.data"]; // 解檔 Student *s = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; NSLog(@"%@----%ld", s.name, s.age);
相關連接:iOS開發中本地數據存儲的總結
以上的全部存儲方法,都是覆蓋存儲。若是想要增長一條數據就必須把整個文件讀出來,而後修改數據後再把整個內容覆蓋寫入文件。因此它們都不適合存儲大量的內容,大量存儲須要用SQLite、CoreData等!
相關連接:ios KeyChain中保存數據
相關連接:使用ASIHTTPRequest和ASIDownloadCache實現本地緩存
一、設置全局的Cache
在AppDelegate.h中添加一個全局變量
@interface AppDelegate : UIResponder { ASIDownloadCache *myCache; } @property (strong, nonatomic) UIWindow *window; @property (nonatomic,retain) ASIDownloadCache *myCache;
//自定義緩存 ASIDownloadCache *cache = [[ASIDownloadCache alloc] init]; self.myCache = cache; [cache release]; //設置緩存路徑 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentDirectory = [paths objectAtIndex:0]; [self.myCache setStoragePath:[documentDirectory stringByAppendingPathComponent:@"resource"]]; [self.myCache setDefaultCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy];
在AppDelegate.m中的dealloc方法中添加以下語句
[myCache release];
二、設置緩存策略
在實現ASIHTTPRequest請求的地方設置request的存儲方式,代碼以下
NSString *str = @"http://....../getPictureNews.aspx"; NSURL *url = [NSURL URLWithString:str]; ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url]; //獲取全局變量 AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; //設置緩存方式 [request setDownloadCache:appDelegate.myCache]; //設置緩存數據存儲策略,這裏採起的是若是無更新或沒法聯網就讀取緩存數據 [request setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy]; request.delegate = self; [request startAsynchronous];
我在這裏採用的是手動清理數據的方式,在適當的地方添加以下代碼,我將清理緩存放在了應用的設置模塊:
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; [appDelegate.myCache clearCachedResponsesForStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
這裏清理的是ASICachePermanentlyCacheStoragePolicy這種存儲策略的緩存數據,若是更換其餘的參數的話,便可清理對應存儲策略的緩存數據。
SQLite3
以前的全部存儲方法,都是覆蓋存儲。若是想要增長一條數據就必須把整個文件讀出來,而後修改數據後再把整個內容覆蓋寫入文件。因此它們都不適合存儲大量的內容。
1.字段類型
表面上SQLite將數據分爲如下幾種類型:
integer : 整數
real : 實數(浮點數)
text : 文本字符串
blob : 二進制數據,好比文件,圖片之類的
實際上SQLite是無類型的。即無論你在創表時指定的字段類型是什麼,存儲是依然能夠存儲任意類型的數據。並且在創表時也能夠不指定字段類型。SQLite之因此什麼類型就是爲了良好的編程規範和方便開發人員交流,因此平時在使用時最好設置正確的字段類型!主鍵必須設置成integer
2. 準備工做
準備工做就是導入依賴庫啦,在iOS中要使用SQLite3,須要添加庫文件:libsqlite3.dylib並導入主頭文件,這是一個C語言的庫,因此直接使用SQLite3仍是比較麻煩的。
3.使用
建立數據庫並打開
操做數據庫以前必須先指定數據庫文件和要操做的表,因此使用SQLite3,首先要打開數據庫文件,而後指定或建立一張表。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
/**
* 打開數據庫並建立一個表
*/
- (void)openDatabase {
//1.設置文件名
NSString *filename = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@
"person.db"
];
//2.打開數據庫文件,若是沒有會自動建立一個文件
NSInteger result = sqlite3_open(filename.UTF8String, &_sqlite3);
if
(result == SQLITE_OK) {
NSLog(@
"打開數據庫成功!"
);
//3.建立一個數據庫表
char *errmsg = NULL;
sqlite3_exec(_sqlite3,
"CREATE TABLE IF NOT EXISTS t_person(id integer primary key autoincrement, name text, age integer)"
, NULL, NULL, &errmsg);
if
(errmsg) {
NSLog(@
"錯誤:%s"
, errmsg);
}
else
{
NSLog(@
"創表成功!"
);
}
}
else
{
NSLog(@
"打開數據庫失敗!"
);
}
}
|
執行指令
使用 sqlite3_exec() 方法能夠執行任何SQL語句,好比創表、更新、插入和刪除操做。可是通常不用它執行查詢語句,由於它不會返回查詢到的數據。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/**
* 往表中插入1000條數據
*/
- (void)insertData {
NSString *nameStr;
NSInteger age;
for
(NSInteger i = 0; i < 1000; i++) {
nameStr = [NSString stringWithFormat:@
"Bourne-%d"
, arc4random_uniform(10000)];
age = arc4random_uniform(80) + 20;
NSString *sql = [NSString stringWithFormat:@
"INSERT INTO t_person (name, age) VALUES('%@', '%ld')"
, nameStr, age];
char *errmsg = NULL;
sqlite3_exec(_sqlite3, sql.UTF8String, NULL, NULL, &errmsg);
if
(errmsg) {
NSLog(@
"錯誤:%s"
, errmsg);
}
}
NSLog(@
"插入完畢!"
);
}
|
查詢指令
前面說過通常不使用 sqlite3_exec() 方法查詢數據。由於查詢數據必需要得到查詢結果,因此查詢相對比較麻煩。示例代碼以下:
sqlite3_prepare_v2() : 檢查sql的合法性
sqlite3_step() : 逐行獲取查詢結果,不斷重複,直到最後一條記錄
sqlite3_coloum_xxx() : 獲取對應類型的內容,iCol對應的就是SQL語句中字段的順序,從0開始。根據實際查詢字段的屬性,使用sqlite3_column_xxx取得對應的內容便可。
sqlite3_finalize() : 釋放stmt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/**
* 從表中讀取數據到數組中
*/
- (void)readData {
NSMutableArray *mArray = [NSMutableArray arrayWithCapacity:1000];
char *sql =
"select name, age from t_person;"
;
sqlite3_stmt *stmt;
NSInteger result = sqlite3_prepare_v2(_sqlite3, sql, -1, &stmt, NULL);
if
(result == SQLITE_OK) {
while
(sqlite3_step(stmt) == SQLITE_ROW) {
char *name = (char *)sqlite3_column_text(stmt, 0);
NSInteger age = sqlite3_column_int(stmt, 1);
//建立對象
Person *person = [Person personWithName:[NSString stringWithUTF8String:name] Age:age];
[mArray addObject:person];
}
self.dataList = mArray;
}
sqlite3_finalize(stmt);
}
|
4.總結
總得來講,SQLite3的使用仍是比較麻煩的,由於都是些c語言的函數,理解起來有些困難。不過在通常開發過程當中,使用的都是第三方開源庫 FMDB,封裝了這些基本的c語言方法,使得咱們在使用時更加容易理解,提升開發效率。
FMDB
1.簡介
FMDB是iOS平臺的SQLite數據庫框架,它是以OC的方式封裝了SQLite的C語言API,它相對於cocoa自帶的C語言框架有以下的優勢:
使用起來更加面向對象,省去了不少麻煩、冗餘的C語言代碼
對比蘋果自帶的Core Data框架,更加輕量級和靈活
提供了多線程安全的數據庫操做方法,有效地防止數據混亂
2.核心類
FMDB有三個主要的類:
FMDatabase
一個FMDatabase對象就表明一個單獨的SQLite數據庫,用來執行SQL語句
FMResultSet
使用FMDatabase執行查詢後的結果集
FMDatabaseQueue
用於在多線程中執行多個查詢或更新,它是線程安全的
3.打開數據庫
和c語言框架同樣,FMDB經過指定SQLite數據庫文件路徑來建立FMDatabase對象,但FMDB更加容易理解,使用起來更容易,使用以前同樣須要導入sqlite3.dylib。打開數據庫方法以下:
1
2
3
4
5
|
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@
"person.db"
];
FMDatabase *database = [FMDatabase databaseWithPath:path];
if
(![database open]) {
NSLog(@
"數據庫打開失敗!"
);
}
|
值得注意的是,Path的值能夠傳入如下三種狀況:
具體文件路徑,若是不存在會自動建立
空字符串@"",會在臨時目錄建立一個空的數據庫,當FMDatabase鏈接關閉時,數據庫文件也被刪除
nil,會建立一個內存中臨時數據庫,當FMDatabase鏈接關閉時,數據庫會被銷燬
4.更新
在FMDB中,除查詢之外的全部操做,都稱爲「更新」, 如:create、drop、insert、update、delete等操做,使用executeUpdate:方法執行更新:
1
2
3
4
5
6
7
8
|
//經常使用方法有如下3種:
- (BOOL)executeUpdate:(NSString*)sql, ...
- (BOOL)executeUpdateWithFormat:(NSString*)format, ...
- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments
//示例
[database executeUpdate:@
"CREATE TABLE IF NOT EXISTS t_person(id integer primary key autoincrement, name text, age integer)"
];
//或者
[database executeUpdate:@
"INSERT INTO t_person(name, age) VALUES(?, ?)"
, @
"Bourne"
, [NSNumber numberWithInt:42]];
|
5.查詢
查詢方法也有3種,使用起來至關簡單:
1
2
3
|
- (FMResultSet *)executeQuery:(NSString*)sql, ...
- (FMResultSet *)executeQueryWithFormat:(NSString*)format, ...
- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments
|
查詢示例:
1
2
3
4
5
6
7
|
//1.執行查詢
FMResultSet *result = [database executeQuery:@
"SELECT * FROM t_person"
];
//2.遍歷結果集
while
([result next]) {
NSString *name = [result stringForColumn:@
"name"
];
int age = [result intForColumn:@
"age"
];
}
|
6.線程安全
在多個線程中同時使用一個FMDatabase實例是不明智的。不要讓多個線程分享同一個FMDatabase實例,它沒法在多個線程中同時使用。 若是在多個線程中同時使用一個FMDatabase實例,會形成數據混亂等問題。因此,請使用 FMDatabaseQueue,它是線程安全的。如下是使用方法:
建立隊列。
1
|
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];
|
使用隊列
1
2
3
4
5
6
7
8
|
[queue inDatabase:^(FMDatabase *database) {
[database executeUpdate:@
"INSERT INTO t_person(name, age) VALUES (?, ?)"
, @
"Bourne_1"
, [NSNumber numberWithInt:1]];
[database executeUpdate:@
"INSERT INTO t_person(name, age) VALUES (?, ?)"
, @
"Bourne_2"
, [NSNumber numberWithInt:2]];
[database executeUpdate:@
"INSERT INTO t_person(name, age) VALUES (?, ?)"
, @
"Bourne_3"
, [NSNumber numberWithInt:3]];
FMResultSet *result = [database executeQuery:@
"select * from t_person"
];
while
([result next]) {
}
}];
|
並且能夠輕鬆地把簡單任務包裝到事務裏:
1
2
3
4
5
6
7
8
9
10
|
[queue inTransaction:^(FMDatabase *database, BOOL *rollback) {
[database executeUpdate:@
"INSERT INTO t_person(name, age) VALUES (?, ?)"
, @
"Bourne_1"
, [NSNumber numberWithInt:1]];
[database executeUpdate:@
"INSERT INTO t_person(name, age) VALUES (?, ?)"
, @
"Bourne_2"
, [NSNumber numberWithInt:2]];
[database executeUpdate:@
"INSERT INTO t_person(name, age) VALUES (?, ?)"
, @
"Bourne_3"
, [NSNumber numberWithInt:3]];
FMResultSet *result = [database executeQuery:@
"select * from t_person"
];
while
([result next]) {
}
//回滾
*rollback = YES;
}];
|
FMDatabaseQueue 後臺會創建系列化的G-C-D隊列,並執行你傳給G-C-D隊列的塊。這意味着 你從多線程同時調用調用方法,GDC也會按它接收的塊的順序來執行。
建立數據庫
CoreData
-> DataModel
Add Entity
Attributes
下方的‘+’號建立模型文件
CoreData
-> NSManaged Object subclass
經過代碼,關聯數據庫和實體
- (void)viewDidLoad { [super viewDidLoad]; /* * 關聯的時候,若是本地沒有數據庫文件,Coreadata本身會建立 */ // 1. 上下文 NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init]; // 2. 上下文關連數據庫 // 2.1 model模型文件 NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil]; // 2.2 持久化存儲調度器 // 持久化,把數據保存到一個文件,而不是內存 NSPersistentStoreCoordinator *store = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model]; // 2.3 設置CoreData數據庫的名字和路徑 NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *sqlitePath = [doc stringByAppendingPathComponent:@"company.sqlite"]; [store addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:sqlitePath] options:nil error:nil]; context.persistentStoreCoordinator = store; _context = context; }
添加元素 - Create
-(IBAction)addEmployee{ // 建立一個員工對象 //Employee *emp = [[Employee alloc] init]; 不能用此方法建立 Employee *emp = [NSEntityDescription insertNewObjectForEntityForName:@"Employee" inManagedObjectContext:_context]; emp.name = @"wangwu"; emp.height = @1.80; emp.birthday = [NSDate date]; // 直接保存數據庫 NSError *error = nil; [_context save:&error]; if (error) { NSLog(@"%@",error); } }
讀取數據 - Read
-(IBAction)readEmployee{ // 1.FetchRequest 獲取請求對象 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"]; // 2.設置過濾條件 // 查找zhangsan NSPredicate *pre = [NSPredicate predicateWithFormat:@"name = %@", @"zhangsan"]; request.predicate = pre; // 3.設置排序 // 身高的升序排序 NSSortDescriptor *heigtSort = [NSSortDescriptor sortDescriptorWithKey:@"height" ascending:NO]; request.sortDescriptors = @[heigtSort]; // 4.執行請求 NSError *error = nil; NSArray *emps = [_context executeFetchRequest:request error:&error]; if (error) { NSLog(@"error"); } //NSLog(@"%@",emps); //遍歷員工 for (Employee *emp in emps) { NSLog(@"名字 %@ 身高 %@ 生日 %@",emp.name,emp.height,emp.birthday); } }
修改數據 - Update
-(IBAction)updateEmployee{ // 改變zhangsan的身高爲2m // 1.查找到zhangsan // 1.1FectchRequest 抓取請求對象 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"]; // 1.2設置過濾條件 // 查找zhangsan NSPredicate *pre = [NSPredicate predicateWithFormat:@"name = %@", @"zhangsan"]; request.predicate = pre; // 1.3執行請求 NSArray *emps = [_context executeFetchRequest:request error:nil]; // 2.更新身高 for (Employee *e in emps) { e.height = @2.0; } // 3.保存 NSError *error = nil; [_context save:&error]; if (error) { NSLog(@"%@",error); } }
刪除數據 - Delete
-(IBAction)deleteEmployee{ // 刪除 lisi // 1.查找lisi // 1.1FectchRequest 抓取請求對象 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"]; // 1.2設置過濾條件 // 查找zhangsan NSPredicate *pre = [NSPredicate predicateWithFormat:@"name = %@", @"lisi"]; request.predicate = pre; // 1.3執行請求 NSArray *emps = [_context executeFetchRequest:request error:nil]; // 2.刪除 for (Employee *e in emps) { [_context deleteObject:e]; } // 3.保存 NSError *error = nil; [_context save:&error]; if (error) { NSLog(@"%@",error); } }
建立數據庫
CoreData
-> DataModel
Add Entity
, 注意:這裏根據關聯添加多個實體Attributes
下方的‘+’號建立模型文件
CoreData
-> NSManaged Object subclass
經過代碼,關聯數據庫和實體
- (void)viewDidLoad { [super viewDidLoad]; /* * 關聯的時候,若是本地沒有數據庫文件,Coreadata本身會建立 */ // 1. 上下文 NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init]; // 2. 上下文關連數據庫 // 2.1 model模型文件 NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil]; // 2.2 持久化存儲調度器 // 持久化,把數據保存到一個文件,而不是內存 NSPersistentStoreCoordinator *store = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model]; // 2.3 設置CoreData數據庫的名字和路徑 NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *sqlitePath = [doc stringByAppendingPathComponent:@"company.sqlite"]; [store addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:sqlitePath] options:nil error:nil]; context.persistentStoreCoordinator = store; _context = context; }
添加元素 - Create
-(IBAction)addEmployee{ // 1. 建立兩個部門 ios android //1.1 iOS部門 Department *iosDepart = [NSEntityDescription insertNewObjectForEntityForName:@"Department" inManagedObjectContext:_context]; iosDepart.name = @"ios"; iosDepart.departNo = @"0001"; iosDepart.createDate = [NSDate date]; //1.2 Android部門 Department *andrDepart = [NSEntityDescription insertNewObjectForEntityForName:@"Department" inManagedObjectContext:_context]; andrDepart.name = @"android"; andrDepart.departNo = @"0002"; andrDepart.createDate = [NSDate date]; //2. 建立兩個員工對象 zhangsan屬於ios部門 lisi屬於android部門 //2.1 zhangsan Employee *zhangsan = [NSEntityDescription insertNewObjectForEntityForName:@"Employee" inManagedObjectContext:_context]; zhangsan.name = @"zhangsan"; zhangsan.height = @(1.90); zhangsan.birthday = [NSDate date]; zhangsan.depart = iosDepart; //2.2 lisi Employee *lisi = [NSEntityDescription insertNewObjectForEntityForName:@"Employee" inManagedObjectContext:_context]; lisi.name = @"lisi"; lisi.height = @2.0; lisi.birthday = [NSDate date]; lisi.depart = andrDepart; //3. 保存數據庫 NSError *error = nil; [_context save:&error]; if (error) { NSLog(@"%@",error); } }
讀取信息 - Read
-(IBAction)readEmployee{ // 讀取ios部門的員工 // 1.FectchRequest 抓取請求對象 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"]; // 2.設置過濾條件 NSPredicate *pre = [NSPredicate predicateWithFormat:@"depart.name = %@",@"android"]; request.predicate = pre; // 4.執行請求 NSError *error = nil; NSArray *emps = [_context executeFetchRequest:request error:&error]; if (error) { NSLog(@"error"); } //遍歷員工 for (Employee *emp in emps) { NSLog(@"名字 %@ 部門 %@",emp.name,emp.depart.name); } }
其餘功能與前幾種相似,這裏不在贅述
準備工做和上面相似,主要是查詢方式不一樣
模糊查詢
-(IBAction)readEmployee{ // 1.FectchRequest 抓取請求對象 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"]; // 2.設置排序 // 按照身高的升序排序 NSSortDescriptor *heigtSort = [NSSortDescriptor sortDescriptorWithKey:@"height" ascending:NO]; request.sortDescriptors = @[heigtSort]; // 3.模糊查詢 // 3.1 名字以"wang"開頭 // NSPredicate *pre = [NSPredicate predicateWithFormat:@"name BEGINSWITH %@",@"wangwu1"]; // request.predicate = pre; // 名字以"1"結尾 // NSPredicate *pre = [NSPredicate predicateWithFormat:@"name ENDSWITH %@",@"1"]; // request.predicate = pre; // 名字包含"wu1" // NSPredicate *pre = [NSPredicate predicateWithFormat:@"name CONTAINS %@",@"wu1"]; // request.predicate = pre; // like 匹配 NSPredicate *pre = [NSPredicate predicateWithFormat:@"name like %@",@"*wu12"]; request.predicate = pre; // 4.執行請求 NSError *error = nil; NSArray *emps = [_context executeFetchRequest:request error:&error]; if (error) { NSLog(@"error"); } //遍歷員工 for (Employee *emp in emps) { NSLog(@"名字 %@ 身高 %@ 生日 %@",emp.name,emp.height,emp.birthday); } }
分頁查詢
-(void)pageSeacher{ // 1. FectchRequest 抓取請求對象 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"]; // 2. 設置排序 // 身高的升序排序 NSSortDescriptor *heigtSort = [NSSortDescriptor sortDescriptorWithKey:@"height" ascending:NO]; request.sortDescriptors = @[heigtSort]; // 3. 分頁查詢 // 總有共有15數據 // 每次獲取6條數據 // 第一頁 0,6 // 第二頁 6,6 // 第三頁 12,6 3條數據 // 3.1 分頁的起始索引 request.fetchOffset = 12; // 3.2 分頁的條數 request.fetchLimit = 6; // 4. 執行請求 NSError *error = nil; NSArray *emps = [_context executeFetchRequest:request error:&error]; if (error) { NSLog(@"error"); } // 5. 遍歷員工 for (Employee *emp in emps) { NSLog(@"名字 %@ 身高 %@ 生日 %@",emp.name,emp.height,emp.birthday); } }
注意:
建立多個數據庫,即建立多個
DataModel
一個數據庫對應一個上下文
須要根據bundle名建立上下文
添加或讀取信息,須要根據不一樣的上下文,訪問不一樣的實體
關聯數據庫和實體
- (void)viewDidLoad { [super viewDidLoad]; // 一個數據庫對應一個上下文 _companyContext = [self setupContextWithModelName:@"Company"]; _weiboContext = [self setupContextWithModelName:@"Weibo"]; } /** * 根據模型文件,返回一個上下文 */ -(NSManagedObjectContext *)setupContextWithModelName:(NSString *)modelName{ // 1. 上下文 NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init]; // 2. 上下文關連數據庫 // 2.1 model模型文件 // 注意:若是使用下面的方法,若是 bundles爲nil 會把bundles裏面的全部模型文件的表放在一個數據庫 //NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil]; // 改成如下的方法獲取: NSURL *companyURL = [[NSBundle mainBundle] URLForResource:modelName withExtension:@"momd"]; NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:companyURL]; // 2.2 持久化存儲調度器 // 持久化,把數據保存到一個文件,而不是內存 NSPersistentStoreCoordinator *store = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model]; // 2.3 告訴Coredata數據庫的名字和路徑 NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *sqliteName = [NSString stringWithFormat:@"%@.sqlite",modelName]; NSString *sqlitePath = [doc stringByAppendingPathComponent:sqliteName]; [store addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:sqlitePath] options:nil error:nil]; context.persistentStoreCoordinator = store; // 3. 返回上下文 return context; }
添加元素
-(IBAction)addEmployee{ // 1. 添加員工 Employee *emp = [NSEntityDescription insertNewObjectForEntityForName:@"Employee" inManagedObjectContext:_companyContext]; emp.name = @"zhagsan"; emp.height = @2.3; emp.birthday = [NSDate date]; // 直接保存數據庫 [_companyContext save:nil]; // 2. 發微博 Status *status =[NSEntityDescription insertNewObjectForEntityForName:@"Status" inManagedObjectContext:_weiboContext]; status.text = @"發了一條微博!"; status.createDate = [NSDate date]; [_weiboContext save:nil]; }