創建資料庫#
1. 首先分析清楚自己需要什麼#
我的目的是要快取信件列表介面,新建列表介面的 model 就是 letter,所以我需要一個 Letter 的實體 (entity),那這個 Letter 有哪些屬性呢?寫信的人 (sender)、信的內容 (content)、信的時間 (dateString)、信的已讀未讀狀態 (isRead)、發信還是收信 (incoming);所以我 Letter 的 entity 創建之後是這樣:
這樣就好嗎,並沒有,如果是普通的展示介面,只有 letter 的實體,這樣就足夠了;但是對於我的這個專案來說,是展示信件的,是比較私人的,我快取的信件列表應該只有我能看到,如果別人在我的手機上登入了呢?因為我沒有做區分,所以,當他登入的時候,他能看到我的數據,因為數據是快取在手機上的!
所以,我需要一個 User 的 Entity,這個 User 的 Entity 的目的是:跟 Letter 綁定,保證每個人都看到自己應該看到的;user 有兩個 attribute:accout 和 writeName,(正常情況下應該是 uid,但是我的這個是比較簡單,所以沒有 uid);
緊接著問題是,Letter 和 User 之間 Relationships,是一對一還是一對多,我的每個 letter 都應該有一個 user,並且只有一個 user,但是我一個 user 應該有很多 letter,當我從資料庫獲取 letter 的時候,其實就是拿著 user 去查找的,當我 user 跟 letter 是一對一的話,那我就只能取出一封信,明顯是不對的。
結論:我的資料庫,有兩個 Entity,一個是 Letter,一個是 User;Letter 和 User 的 Relationships 的 type 是一對一,User 和 Letter 的 Relationships 的 type 是一對多;
2. 然後導入MagicalRecord#
我之前快取數據一直都是使用的 FMDB,沒用過 CoreData,但是當我在拆分成徹底的 MVC 的時候,我總是希望我可以直接拿著這個 model 就可以存儲,取出來就是 model,就可以直接使用,而不是一個個屬性,再重新賦值,所以我就想嘗試一下 CoreData;但原生的太複雜,所以就選擇 MagicalRecord。
MagicalRecord 的使用: github 上只有各個方法的使用,但是我沒找到 Demo,所以我把我是如何使用的貼出來,僅供參考
在 pch 文件裡,導入頭文件
a. 在 applicationDidFinishLaunchingWithOptions: 裡初始化
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
[MagicalRecord setupAutoMigratingCoreDataStack];
// 設置window的rootViewController
[self setupWindowRootViewController];
return YES;
}
b. 在程序停止時,調用 cleanup 方法
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
[MagicalRecord cleanUp];
}
c. 生成 model 類
選中.xcdatamodeld 文件,CMD+N,
全部勾選,然後生成 model 類
d. 網路請求成功後,順便保存數據
// 將letter保存到資料庫
- (void)saveLetterWithLetterEntity:(LetterEntity *)tempLetter {
// MagicalRecord保存的方法,不是主線程
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
// 首先,通過pkNumber查詢,得到letter
// 如果letter不存在,則創建
// 賦值保存,注意這裡的user.lettters是NSSet,因為
Letter *letter = [Letter MR_findFirstByAttribute:@"pkNumber" withValue:tempLetter.pkNumber inContext:localContext];
if (!letter) {
// 創建letter
letter = [Letter MR_createEntityInContext:localContext];
User *user = [User MR_createEntityInContext:localContext];
letter.user = user;
}
letter.dateString = tempLetter.letterDateString;
letter.content = tempLetter.letterContent;
letter.sender = tempLetter.letterSender;
letter.pkNumber = tempLetter.pkNumber;
letter.incoming = [NSNumber numberWithBool:tempLetter.incoming];
// 收信默認為未讀,發信默認都是已讀
if (tempLetter.incoming) {
// 收信
letter.isRead = [NSNumber numberWithBool:NO];
}
else {
letter.isRead = [NSNumber numberWithBool:YES];
}
letter.user.writeName = [[NSUserDefaults standardUserDefaults] objectForKey:k_WRITENAME];
letter.user.account = [[NSUserDefaults standardUserDefaults] objectForKey:k_USERNAME];
if (_letters == nil) {
_letters = [NSMutableArray array];
}
[_letters addObject:letter];
letter.user.letters = [NSSet setWithArray:_letters];
} completion:^(BOOL contextDidSave, NSError *error) {
DLog(@"=-===%@", (contextDidSave ? @"saveSuccessed" : @"saveFailure"));
}];
}
e. 網路失敗時從資料庫獲取數據
- (NSMutableArray *)lettersFromDataBase {
NSMutableArray *receiveArray = [NSMutableArray array];
NSMutableArray *sendArray = [NSMutableArray array];
NSString *account = [[NSUserDefaults standardUserDefaults] objectForKey:k_USERNAME];
User *user = [[User MR_findByAttribute:@"account" withValue:account] firstObject];
// NSPredicate *receivePredicate = [NSPredicate predicateWithFormat:@"incoming == %@ && user == %@", [NSNumber numberWithBool:YES], user];
// NSPredicate *sendPredicate = [NSPredicate predicateWithFormat:@"incoming == %@ && user == %@", [NSNumber numberWithBool:NO], user];
// receiveArray = [NSMutableArray arrayWithArray:[Letter MR_findAllWithPredicate:receivePredicate]];
// sendArray = [NSMutableArray arrayWithArray:[Letter MR_findAllWithPredicate:sendPredicate]];
NSArray *userLetters = [Letter MR_findByAttribute:@"user" withValue:user];
if (userLetters) {
for (int i = 0; i < userLetters.count; i++) {
Letter *tempLetter = userLetters[i];
LetterEntity *tempEntity = [[LetterEntity alloc] init];
tempEntity.letterContent = tempLetter.content;
tempEntity.letterDateString = tempLetter.dateString;
tempEntity.letterSender = tempLetter.sender;
tempEntity.pkNumber = tempLetter.pkNumber;
tempEntity.incoming = [tempLetter.incoming boolValue];
if ([tempLetter.incoming boolValue]) {
[receiveArray addObject:tempEntity];
}
else {
[sendArray addObject:tempEntity];
}
}
}
// 這裡的順序不能錯,sendArray在前,receiveArray在後面
NSMutableArray *resultArray = [NSMutableArray arrayWithObjects: sendArray, receiveArray, nil];
return resultArray;
}
參考#
-
深入淺出 MagicalRecord,這篇博客講的很詳細,從 CoreData 到 MagicalRecord
-
RayWenderlich 的 MagicalRecord Tutorial,這篇是教程,可以跟著敲,練習