データベースの作成#
1. まず自分が何を必要としているかを分析する#
私の目的は、手紙リストのインターフェースをキャッシュすることです。新しいリストインターフェースのモデルは letter です。したがって、Letter のエンティティが必要です。この Letter にはどのような属性がありますか?書き手 (sender)、手紙の内容 (content)、手紙の時間 (dateString)、手紙の既読未読状態 (isRead)、送信か受信か (incoming);したがって、私の Letter のエンティティはこのように作成されます:
これで十分ですか?いいえ、もし普通の表示インターフェースであれば、letter のエンティティだけで十分です。しかし、私のこのプロジェクトは手紙を表示するものであり、比較的プライベートです。私がキャッシュした手紙リストは、私だけが見るべきです。他の誰かが私の携帯電話にログインした場合はどうなりますか?区別をしていないため、彼がログインすると、私のデータが見えてしまいます。データは携帯電話にキャッシュされているからです!
したがって、User のエンティティが必要です。この User のエンティティの目的は:Letter とバインドし、各人が自分が見るべきものを見られるようにすることです;user には 2 つの属性があります:account と writeName(通常は uid であるべきですが、私のは比較的簡単なので uid はありません);
次の問題は、Letter と User の間の Relationships が一対一か一対多かです。私の各 letter には 1 つの user が必要であり、1 つの user には多くの letter があります。データベースから letter を取得するとき、実際には user を使って検索しています。user と letter が一対一の場合、1 通の手紙しか取得できず、明らかに間違っています。
結論:私のデータベースには 2 つのエンティティがあります。1 つは Letter、もう 1 つは User です。Letter と User の Relationships のタイプは一対一であり、User と Letter の Relationships のタイプは一対多です;
2. 次にMagicalRecordをインポートする#
私は以前、データをキャッシュする際に FMDB を使用しており、CoreData を使用したことはありませんでした。しかし、MVC に完全に分割する際に、モデルを直接使って保存し、取り出すとモデルとして直接使用できることを望んでいました。属性を一つ一つ再代入するのではなく、CoreData を試してみたいと思いました。しかし、原生のものは非常に複雑なので、MagicalRecord を選びました。
MagicalRecord の使用:github には各メソッドの使用法しかありませんが、デモを見つけられなかったので、私がどのように使用したかを貼り付けます。参考までに。
pch ファイルにヘッダーファイルをインポートします。
a. applicationDidFinishLaunchingWithOptions: で初期化します。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// アプリケーション起動後のカスタマイズポイント。
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
[MagicalRecord setupAutoMigratingCoreDataStack];
// windowのrootViewControllerを設定
[self setupWindowRootViewController];
return YES;
}
b. アプリケーションが停止する際に cleanup メソッドを呼び出します。
- (void)applicationWillTerminate:(UIApplication *)application {
// アプリケーションが終了しようとしています。適切にデータを保存します。applicationDidEnterBackground:も参照してください。
[MagicalRecord cleanUp];
}
c. モデルクラスを生成します。
.xcdatamodeld ファイルを選択し、CMD+N を押します。
すべて選択し、モデルクラスを生成します。
d. ネットワークリクエストが成功した後、データを保存します。
// letterをデータベースに保存する
- (void)saveLetterWithLetterEntity:(LetterEntity *)tempLetter {
// MagicalRecordの保存メソッド、メインスレッドではない
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
// まず、pkNumberで検索し、letterを取得
// letterが存在しない場合は作成
// 値を設定して保存します。ここでのuser.lettersは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、このチュートリアルは、手を動かしながら練習できます。