iOS developing note part3 Use CoreData framework with MagicRecord

In last project (the cancelled one), I was trying to find a handy way to store my location data, the relationship will be like this.

Location(data generated by GPS module, contains coordination information)

–> Action (contains several locations data, and some properties for motion detection)

–> DailyActions (daily datas,contains several actions, and some summary info)

Now, here comes a question:

If I want to learn excavators driving, which school will be the best choice?

Ah, no,no,no, WTF!! What happens on me~

Array –> File Way

The question is, I store them in object array, then write them to a file, if I want to modify any sub node, for example: I want to change date:2014-10-10’s action which is a running action which happened in afternoon’s some of that locations to filter out the exception data, and recalculate the total calories casted again……don’t know what I’m talking.

I mean,you need to locate this location object from the root node, then track them by looping every sub nodes. there is no more efficient way to do this if you choose a Array–>File way.

Another bad thing for Array–>File way is, you have to let every class of object implements NSCoding protocol, and the lengthy syntax’s gonna make any extending harder.

With the number of data growing, the file will become such a fat ass, but for the functional requirement, you have to load it every time,or you can create a new way to make it work, like cache.

SQLite Way

What about sqlite? Just like any structure database, it is formal, common, and high performance. And the bad side is, you need to learn some SQL script, the basic CURD syntax. And for some scenarios, you might need the data more objective, you have to convert a row of data from database table to a object, instead of changing all the data by string like this every time.

update member set member_type = 'Star' where id in (select id from member where score > 1000)

But It is still a worth trying way, I will try this later.

CoreData

CoreData is a solution that Apple provided between Array–>File and SQLite, I think. Apple described this very implicitly, it is a document based database or a objective memory based database, in my view, it include both features from them.

But, like other apple development things, it was not so easy to use, it has become a much-maligned problem, the answers I got from stackoverflow.com and much more then I got from  apple’s official documents, sometimes I feel like searching a saint’s name in the bible, but all I need is a simple “Hallelujah”.

MagicRecord

Luckily, there always someone met the same problem before me, so they create a “Super Awesome Easy Fetching for Core Data” framework named MagicRecord .

1. Install it with cocoapods, with

pod "MagicalRecord"

2.Create a Data Model File:

3 Setup entities, if you have OOP background knowledges, this will be pretty easy to do.

4. Build relationships between entities, e.g. a option belongs to a question, a question has several options. click “+” below Relationships table. Give a name of relationship. It seems like Core Data need  relationship between Entities can relate each other. so if you don’t choose a inverse for it, you will get a warning.

Consistency Error: QuestionObject.options does not have an inverse; this is an advanced setting (no object can be in multiple destinations for a specific relationship)

Setup one firstly, than to the target entity, and build the match relationship.

5. One to Many relationship, you can find it here:

6. Setup MagicRecord. Insert code to any where you like, just make sure it is executed before data handling. I recommend to run it here

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [MagicalRecord setupCoreDataStackWithAutoMigratingSqliteStoreNamed:@"EbolaQuiz.sqlite"];
    return YES;
}

7. Generate NSManagedObject Subclass, Xcode will do this for you.

8. Now we can see what’s happened,

As you can see, the class file contains all the attributes, and converted them to properties, a one to many relationship is presented as a NSSet property.

9. Create an data object by:

OptionObject *option = [OptionObject MR_createEntity];

YES!! Just 1 line code!! And if you wanna do this with original Core Data, it will take nearly hundred lines of code. That is why it’s called “Magical”.

10. Assign value to the object, then save it:

OptionObject *option = [OptionObject MR_createEntity];
option.id = @"1";
option.statement = @"Option A";
[self save];

the save method

- (void)save {
    [[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) {
        if (success) {
            NSLog(@"You successfully saved your context.");
        } else if (error) {
            NSLog(@"Error saving context: %@", error.description);
        }
    }];
}

If it runs correctly, there will be a log appears like this:

2014-10-11 17:25:17.960 EbolaQuiz[63543:5180420] You successfully saved your context.

11. Setup relationship between entities:

QuestionObject *question = [QuestionObject MR_createEntity];
question.id = @"1";
question.subject = @"This is a question.";
question.desc = @"Yes it is just a question.";

OptionObject *option = [OptionObject MR_createEntity];
option.id = @"1-1";
option.statement = @"Option A";

option.questionBelongsTo = question;
[question addOptionsObject:option];
[self save];

12 . Find(or Fetch) Data:

QuestionObject *question = [QuestionObject MR_findFirst];
NSLog(@"Question '%@' have %zd options",question.subject,question.options.count);

13. Find(or Fetch) Data by predicate:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"id == %d ",1];
NSArray *datas = [QuestionObject MR_findAllSortedBy:@"id" ascending:YES withPredicate:predicate];
NSLog(@"There are %zd questions with id == 1",datas.count);

14. Delete a data:

[question MR_deleteEntity];
[self save];

Well, I think it’s enough for start-up using MagicalRecord.

 

Search China ShanDong Blue Fly!!