Hello I am Riccardo and I am an indie developer!
it's not a lot that I have been starting programming in objective-c, and I am still a novice! :D
I started to learn Core Data and everything was going fine until I faced concurrency! With Core Data my app was continuing to block during save actions, so I googled for core data with background context and I found Magical Record.
With Magical Record I have drastically reduced the complexity of my code :) But I have still one problem, I read everything about Magical Record, I tried to fix it using different methods but the UI freeze is still there :( so I don't know how to fix it...
Although I think there are problem in all method (looking at freeze UI) 3 of the 4 methods listed are really fast so it is not perceptible. The only method that as huge problem and you can actually notice a freeze is this one -->
Where I take an array in order to create all the apps objects and after I associate (after a fetch to find the research, I use the dictionary to create predicates) these apps to the research.
This is my code. It is actually a whole class that manage core data stuff. I don't use queues or threads in the class that call these methods, so I think there is something to fix here :-/
I thank you in advance :)
#import "CoreDataHelper.h"
#import "CoreData+MagicalRecord.h"
@implementation CoreDataHelper
#pragma mark - Research creator helper
+ (ResearchType *) fetchResearchWithDictionary: (NSDictionary *) info {
// Fetch
// predicates for fetch
NSPredicate * predicateCategory = [NSPredicate predicateWithFormat:@"researchCategory = %@" , [info objectForKey: @"Category"]];
NSPredicate * predicateType = [NSPredicate predicateWithFormat:@"researchType = %@" , [info objectForKey: @"Type"]];
NSPredicate * predicatePrefix = [NSPredicate predicateWithFormat:@"researchPrefix = %@" , [info objectForKey: @"Prefix"]];
NSArray * predicates = [NSArray arrayWithObjects: predicateCategory, predicateType, predicatePrefix, nil];
// create the composite predicate
NSPredicate * predicateComposito = [NSCompoundPredicate andPredicateWithSubpredicates:predicates];
// obtain the result
// Passo la ricerca al brain
return [ResearchType MR_findFirstWithPredicate: predicateComposito];
}
+ (void)updateResearchWithDictionary:(NSDictionary *) info withCompletionBlock:(completion_block)updatedResearch {
// Get the context
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_context];
// predicates
NSPredicate * predicateCategory = [NSPredicate predicateWithFormat:@"researchCategory = %@" , [info objectForKey: @"Category"]];
NSPredicate * predicateType = [NSPredicate predicateWithFormat:@"researchType = %@" , [info objectForKey: @"Type"]];
NSPredicate * predicatePrefix = [NSPredicate predicateWithFormat:@"researchPrefix = %@" , [info objectForKey: @"Prefix"]];
NSArray * predicates = [NSArray arrayWithObjects: predicateCategory, predicateType, predicatePrefix, nil];
// composite predicate
NSPredicate * predicateComposito = [NSCompoundPredicate andPredicateWithSubpredicates:predicates];
// create research object
ResearchType *research = [ResearchType MR_findFirstWithPredicate: predicateComposito inContext:localContext];
// new properties
research.researchDate = [info objectForKey:@"Research Date"];
research.researchLimit = [info objectForKey:@"Limit"];
//research.apps = nil;
[localContext MR_saveInBackgroundCompletion:^{
updatedResearch(research);
}];
}
+ (void) persistResearchWithDictionary: (NSDictionary *) info withCompletionBlock:(completion_block)savedResearch {
// Get the context
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_context];
// Create a new Person in the current thread context
ResearchType * research = [ResearchType MR_createInContext:localContext];
// Set properties
research.researchCategory = [info objectForKey: @"Category"];
research.researchPrefix = [info objectForKey: @"Prefix"];
research.researchCategoryUrl = [info objectForKey: @"Category Code Url"];
research.researchType = [info objectForKey: @"Type"];
research.researchCountry = [info objectForKey: @"Country"];
research.researchCountryCode = [info objectForKey: @"Country Code"];
research.researchDate = [info objectForKey: @"Research Date"];
research.researchDevice = [info objectForKey: @"Device"];
research.researchLimit = [info objectForKey: @"Limit"];
// Save changes
[localContext MR_saveInBackgroundCompletion:^{
savedResearch(research);
}];
}
+ (void) persistAppsFromArray: (NSArray *) arrayOfApps inResearch: (NSDictionary *) info {
// Get the local context
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_context];
[localContext MR_saveInBackgroundCompletion:^{
// predicates
NSPredicate * predicateCategory = [NSPredicate predicateWithFormat:@"researchCategory = %@" , [info objectForKey: @"Category"]];
NSPredicate * predicateType = [NSPredicate predicateWithFormat:@"researchType = %@" , [info objectForKey: @"Type"]];
NSPredicate * predicatePrefix = [NSPredicate predicateWithFormat:@"researchPrefix = %@" , [info objectForKey: @"Prefix"]];
NSArray * predicates = [NSArray arrayWithObjects: predicateCategory, predicateType, predicatePrefix, nil];
// Composite predicate
NSPredicate * predicateComposito = [NSCompoundPredicate andPredicateWithSubpredicates:predicates];
ResearchType * researchBgContext = [ResearchType MR_findFirstWithPredicate: predicateComposito];
for (NSDictionary * info in arrayOfApps) {
AppInDb * app = [AppInDb MR_createEntity];
app.appName = [info objectForKey: @"App Name"];
app.appItunesLink = [info objectForKey: @"iTunes Link"];
app.appBundleID = [info objectForKey: @"Bundle ID"];
app.appID = [info objectForKey: @"ID"];
app.appPriceLabel = [info objectForKey: @"Price Label"];
app.appReleaseDate = [info objectForKey: @"Release Date String"];
app.appIconImageLink = [info objectForKey: @"Image Link 100"];
app.appDeveloperPageLink = [info objectForKey: @"Developer Page Link"];
app.appDeveloper = [info objectForKey: @"Developer"];
app.appRights = [info objectForKey: @"Rights"];
app.appDescription = [info objectForKey: @"App Description"];
app.appCategory = [info objectForKey: @"App Category"];
app.appCategoryNumber = [info objectForKey: @"Category Number For Url"];
// adding app to the related research (one to many relationship)
[researchBgContext addAppsObject:app];
}
}];
}
Try with this method:
[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext)block { }];
There are a number of other methods you can use, but this should give you a good start. MagicalRecord will create the context for you and everything happens on the background thread. It will also save to the parent context automatically.
I recommend reading this great article: Core Data and Threads, Without the Headache by Saul Mora who's the person behind MagicalRecord. It's a great read which informs you about the many advantages of MagicalRecord.
Good luck!