Reputation: 1107
I'm new to MagicalRecord. I have a problem updating same entities from different methods. This is my example: I have some Ads that I get from web service. When this completes, I need to update Ads in database if there is any an set their active attribute to 0. Immediately, I need to call Save function in which I store my Ads or just update them. After that I need to delete every Ads with expired date and after that delete inactive ads. These Ads are actually language based, so every time I change language of my application, some ads becomes inactive. It needs to be like that. This is my code for saving and deleting:
- (void) saveBanners:(NSDictionary *)activeBanner
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"];
if (activeBanner != nil || [activeBanner count] != 0)
{
for (int i = 0; i<[activeBanner.banners count]; i++)
{
NSDate *dateTo = [formatter dateFromString:[activeBanner.banners[i] DateValidTo]];
NSDate *dateFrom = [formatter dateFromString:[activeBanner.banners[i] DateValidFrom]];
NSLog(@"%@ %@", dateTo, [activeBanner.banners[i] DateValidTo]);
[MagicalRecord
saveWithBlock:^(NSManagedObjectContext *localContext)
{
Banner *banner = [Banner MR_findFirstByAttribute:@"serverId" withValue:[activeBanner.banners[i] ID] inContext:localContext];
Banner *localBanner;
if (banner != nil)
{
localBanner = [banner MR_inContext:localContext];
}
else
{
localBanner = [Banner MR_createInContext:localContext];
}
localBanner.serverId = [activeBanner.banners[i] ID];
localBanner.name = [activeBanner.banners[i] Name];
localBanner.text = [activeBanner.banners[i] BannerText];
localBanner.dateFrom = dateFrom;
localBanner.dateTo = dateTo;
localBanner.image = [activeBanner.banners[i] ImageData];
localBanner.active = [NSNumber numberWithBool:YES];
localBanner.country = [activeBanner.banners[i] CountryCode];
}];
}
}
}
- (void)setBannerInactive:(NSString *)country
{
NSPredicate *bannerFilter = [NSPredicate predicateWithFormat:@"country IN %@", @[[country uppercaseString]]]; // paziti na upperCase, tako vraca u bazi
NSArray *banners = [Banner MR_findAllWithPredicate:bannerFilter];
NSNumber *bannersCount = [Banner MR_numberOfEntitiesWithPredicate:bannerFilter];
if (bannersCount.integerValue != 0)
{
for (int i = 0; i < bannersCount.integerValue; i++)
{
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext)
{
Banner *banner = [Banner MR_findFirstByAttribute:@"serverId" withValue:[banners[i] serverId] inContext:localContext];
if (banner != nil)
{
Banner *localBanner = [banner MR_inContext:localContext];
localBanner.active = [NSNumber numberWithBool:NO];
}
} completion:^(BOOL success, NSError *error) {
NSLog(@"I am here");
}];
}
}
}
- (void)deleteInactiveBanners
{
NSPredicate *inactiveBannerFilter = [NSPredicate predicateWithFormat:@"active = NO"]; // NO = neaktivni
NSArray *banners = [Banner MR_findAllWithPredicate:inactiveBannerFilter];
if (banners != nil || [banners count] != 0)
{
for (int i = 0; i < [banners count]; i++)
{
Banner *banner = banners[i];
if (banner != nil)
{
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext)
{
Banner *localBanner = [banner MR_inContext:localContext];
[localBanner MR_deleteEntity];
}];
}
}
}
}
I call them in my view controller from my view model in completed block of my RAC signal fetching my ads:
[self.viewModel setBannerInactive:appLanguage];
if (self.viewModel.activeBanner != nil)
{
[self.viewModel saveBanner:self.splashViewModel.activeBanner];
}
[self.viewModel deleteInactiveBanners];
I know that saveWithBlocks is executed in background thread. The problem is when I call setBannerInactive, it does not complete for the time when saveBanners is called so everything does not work as it should. How to properly call these method with MagicalRecord. I'm using latest 2.x MagicalRecord, not v3.?
Upvotes: 0
Views: 87
Reputation: 417
Something like this (I didn't try it nor try to compile it so it may contains errors but the idea is there)
- (void) saveBanners:(NSDictionary *)activeBanner withCompletion:(void(^)())completionBlock
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"];
if (activeBanner != nil || [activeBanner count] != 0)
{
for (int i = 0; i<[activeBanner.banners count]; i++)
{
NSDate *dateTo = [formatter dateFromString:[activeBanner.banners[i] DateValidTo]];
NSDate *dateFrom = [formatter dateFromString:[activeBanner.banners[i] DateValidFrom]];
NSLog(@"%@ %@", dateTo, [activeBanner.banners[i] DateValidTo]);
[MagicalRecord
saveWithBlock:^(NSManagedObjectContext *localContext)
{
Banner *banner = [Banner MR_findFirstByAttribute:@"serverId" withValue:[activeBanner.banners[i] ID] inContext:localContext];
Banner *localBanner;
if (banner != nil)
{
localBanner = [banner MR_inContext:localContext];
}
else
{
localBanner = [Banner MR_createInContext:localContext];
}
localBanner.serverId = [activeBanner.banners[i] ID];
localBanner.name = [activeBanner.banners[i] Name];
localBanner.text = [activeBanner.banners[i] BannerText];
localBanner.dateFrom = dateFrom;
localBanner.dateTo = dateTo;
localBanner.image = [activeBanner.banners[i] ImageData];
localBanner.active = [NSNumber numberWithBool:YES];
localBanner.country = [activeBanner.banners[i] CountryCode];
} completion:^(BOOL success, NSError *error) {
if(completionBlock)
completionBlock();
NSLog(@"I am here");
}];
}
}
}
- (void)setBannerInactive:(NSString *)country withCompletion:(void(^)())completionBlock
{
NSPredicate *bannerFilter = [NSPredicate predicateWithFormat:@"country IN %@", @[[country uppercaseString]]]; // paziti na upperCase, tako vraca u bazi
NSArray *banners = [Banner MR_findAllWithPredicate:bannerFilter];
NSNumber *bannersCount = [Banner MR_numberOfEntitiesWithPredicate:bannerFilter];
if (bannersCount.integerValue != 0)
{
for (int i = 0; i < bannersCount.integerValue; i++)
{
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext)
{
Banner *banner = [Banner MR_findFirstByAttribute:@"serverId" withValue:[banners[i] serverId] inContext:localContext];
if (banner != nil)
{
Banner *localBanner = [banner MR_inContext:localContext];
localBanner.active = [NSNumber numberWithBool:NO];
}
} completion:^(BOOL success, NSError *error) {
NSLog(@"I am here");
if(completionBlock)
completionBlock();
}];
}
}
}
- (void)deleteInactiveBanners withCompletion:(void(^)())completionBlock
{
NSPredicate *inactiveBannerFilter = [NSPredicate predicateWithFormat:@"active = NO"]; // NO = neaktivni
NSArray *banners = [Banner MR_findAllWithPredicate:inactiveBannerFilter];
if (banners != nil || [banners count] != 0)
{
for (int i = 0; i < [banners count]; i++)
{
Banner *banner = banners[i];
if (banner != nil)
{
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext)
{
Banner *localBanner = [banner MR_inContext:localContext];
[localBanner MR_deleteEntity];
} completion:^(BOOL success, NSError *error) {
NSLog(@"I am here");
if(completionBlock)
completionBlock();
}];
}
}
}
}
using it like this
[self.viewModel setBannerInactive:appLanguage withCompletion:^(){
if (self.viewModel.activeBanner != nil)
{
[self.viewModel saveBanner:self.splashViewModel.activeBanner withCompletion:^(){
[self.viewModel deleteInactiveBanners withCompletion:nil];
}];
}
else
{
[self.viewModel deleteInactiveBanners withCompletion:nil];
}
}];
Upvotes: 1