今是昨非

今是昨非

日出江花红胜火,春来江水绿如蓝

MagicalRecordの使用

データベースの作成#

1. まず自分が何を必要としているかを分析する#

私の目的は、手紙リストのインターフェースをキャッシュすることです。新しいリストインターフェースのモデルは letter です。したがって、Letter のエンティティが必要です。この Letter にはどのような属性がありますか?書き手 (sender)、手紙の内容 (content)、手紙の時間 (dateString)、手紙の既読未読状態 (isRead)、送信か受信か (incoming);したがって、私の Letter のエンティティはこのように作成されます:

image1

これで十分ですか?いいえ、もし普通の表示インターフェースであれば、letter のエンティティだけで十分です。しかし、私のこのプロジェクトは手紙を表示するものであり、比較的プライベートです。私がキャッシュした手紙リストは、私だけが見るべきです。他の誰かが私の携帯電話にログインした場合はどうなりますか?区別をしていないため、彼がログインすると、私のデータが見えてしまいます。データは携帯電話にキャッシュされているからです!

したがって、User のエンティティが必要です。この User のエンティティの目的は:Letter とバインドし、各人が自分が見るべきものを見られるようにすることです;user には 2 つの属性があります:account と writeName(通常は uid であるべきですが、私のは比較的簡単なので uid はありません);

image2

次の問題は、Letter と User の間の Relationships が一対一か一対多かです。私の各 letter には 1 つの user が必要であり、1 つの user には多くの letter があります。データベースから letter を取得するとき、実際には user を使って検索しています。user と letter が一対一の場合、1 通の手紙しか取得できず、明らかに間違っています。
image3

image4

結論:私のデータベースには 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 を押します。

image5

すべて選択し、モデルクラスを生成します。

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;
}

参考#

  1. 深入浅出 MagicalRecord、このブログは非常に詳細に説明しており、CoreData から MagicalRecord までの内容です。

  2. RayWenderlich の MagicalRecord Tutorial、このチュートリアルは、手を動かしながら練習できます。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。