[Cocoa] go deep into core data of cocoa (2)-write code manually

Source: Internet
Author: User

In-depth introduction to cocoa core data (2)-sample code

Luo chaohui (http://blog.csdn.net/kesalin)

CC license. For more information, see Source

We have explained in detail the core data framework and the design classes. Next we will explain an example of using these classes by writing code completely manually. This example is from the official example of apple. In this example, we plan to record the program running record (time and process ID) and save it to the XML file. We use core data to do this.

Download Sample Code: click here

1. Create a new Mac command-line tool application project named coredatatutorial. To support the garbage collection mechanism, click the project name and search for the garbage keyword in build setting on the right, set the objective-C garbage collection to required [-fobj-GC-only]. Modify the main () method in Main. m to the following:

int main (int argc, const char * argv[]){    NSLog(@" === Core Data Tutorial ===");    // Enable GC    //    objc_startCollectorThread();        return 0;}

2. Create and set model classes

Add the following method before Main:

NSManagedObjectModel *managedObjectModel(){    static NSManagedObjectModel *moModel = nil;    if (moModel != nil) {        return moModel;    }        moModel = [[NSManagedObjectModel alloc] init];        // Create the entity    //    NSEntityDescription *runEntity = [[NSEntityDescription alloc] init];    [runEntity setName:@"Run"];    [runEntity setManagedObjectClassName:@"Run"];        [moModel setEntities:[NSArray arrayWithObject:runEntity]];        // Add the Attributes    //    NSAttributeDescription *dateAttribute = [[NSAttributeDescription alloc] init];    [dateAttribute setName:@"date"];    [dateAttribute setAttributeType:NSDateAttributeType];    [dateAttribute setOptional:NO];        NSAttributeDescription *idAttribute = [[NSAttributeDescription alloc] init];    [idAttribute setName:@"processID"];    [idAttribute setAttributeType:NSInteger32AttributeType];    [idAttribute setOptional:NO];    [idAttribute setDefaultValue:[NSNumber numberWithInteger:-1]];    // Create the validation predicate for the process ID.    // The following code is equivalent to validationPredicate = [NSPredicate predicateWithFormat:@"SELF > 0"]    //    NSExpression *lhs = [NSExpression expressionForEvaluatedObject];    NSExpression *rhs = [NSExpression expressionForConstantValue:[NSNumber numberWithInteger:0]];        NSPredicate *validationPredicate = [NSComparisonPredicate                                        predicateWithLeftExpression:lhs                                        rightExpression:rhs                                        modifier:NSDirectPredicateModifier                                        type:NSGreaterThanPredicateOperatorType                                        options:0];        NSString *validationWarning = @"Process ID < 1";    [idAttribute setValidationPredicates:[NSArray arrayWithObject:validationPredicate]                  withValidationWarnings:[NSArray arrayWithObject:validationWarning]];        // set the properties for the entity.    //    NSArray *properties = [NSArray arrayWithObjects: dateAttribute, idAttribute, nil];    [runEntity setProperties:properties];        // Add a Localization Dictionary    //    NSMutableDictionary *localizationDictionary = [NSMutableDictionary dictionary];    [localizationDictionary setObject:@"Date" forKey:@"Property/date/Entity/Run"];    [localizationDictionary setObject:@"Process ID" forKey:@"Property/processID/Entity/Run"];    [localizationDictionary setObject:@"Process ID must not be less than 1" forKey:@"ErrorString/Process ID < 1"];        [moModel setLocalizationDictionary:localizationDictionary];        return moModel;}

In the above Code:

1) We have created a global model momodel;
2) create an entity named run in it, and the corresponding managedobject class named run (we will create such a class soon );
3) added two required properties: Date and processid to run entity, indicating the running time and process ID respectively, and set the default process ID to-1;
4) set the test condition for the processid feature: It must be greater than 0;
5) set a localized description dictionary for the model;

The localized Description provides easy-to-understand descriptions of entity, property, and error information. The available key-value pairs are as follows:

Key

Value


"Entity/nonlocalizedentityname"

"Localizedentityname"

"Property/nonlocalizedpropertyname/entity/entityname"

"Localizedpropertyname"

"Property/nonlocalizedpropertyname"

"Localizedpropertyname"

"Errorstring/nonlocalizederrorstring"

"Localizederrorstring"

3. Create and set runtime classes and objects

To use the storage function, we must define the storage path for persistent data. Before main (), add the following method to set the storage path:

NSURL *applicationLogDirectory(){    NSString *LOG_DIRECTORY = @"CoreDataTutorial";    static NSURL *ald = nil;        if (ald == nil)    {        NSFileManager *fileManager = [[NSFileManager alloc] init];        NSError *error = nil;        NSURL *libraryURL = [fileManager URLForDirectory:NSLibraryDirectory inDomain:NSUserDomainMask                                       appropriateForURL:nil create:YES error:&error];        if (libraryURL == nil) {            NSLog(@"Could not access Library directory\n%@", [error localizedDescription]);        }        else        {            ald = [libraryURL URLByAppendingPathComponent:@"Logs"];            ald = [ald URLByAppendingPathComponent:LOG_DIRECTORY];                        NSLog(@" >> log path %@", [ald path]);                        NSDictionary *properties = [ald resourceValuesForKeys:[NSArray arrayWithObject:NSURLIsDirectoryKey] error:&error];            if (properties == nil)            {                if (![fileManager createDirectoryAtPath:[ald path] withIntermediateDirectories:YES attributes:nil error:&error])                {                    NSLog(@"Could not create directory %@\n%@",                          [ald path], [error localizedDescription]);                    ald = nil;                }            }        }    }        return ald;}

In the above Code, we save the persistent data file to the path:/Users/kesalin/library/logs/coredatatutorial.

Next, we will create a runtime object: managedobjectcontext and persistentstorecoordinator.

NSManagedObjectContext *managedObjectContext(){    static NSManagedObjectContext *moContext = nil;    if (moContext != nil) {        return moContext;    }        moContext = [[NSManagedObjectContext alloc] init];        // Create a persistent store coordinator, then set the coordinator for the context.    //    NSManagedObjectModel *moModel = managedObjectModel();    NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:moModel];    [moContext setPersistentStoreCoordinator: coordinator];        // Create a new persistent store of the appropriate type.     //    NSString *STORE_TYPE = NSXMLStoreType;    NSString *STORE_FILENAME = @"CoreDataTutorial.xml";        NSError *error = nil;    NSURL *url = [applicationLogDirectory() URLByAppendingPathComponent:STORE_FILENAME];        NSPersistentStore *newStore = [coordinator addPersistentStoreWithType:STORE_TYPE                                                            configuration:nil                                                                      URL:url                                                                  options:nil                                                                    error:&error];        if (newStore == nil) {        NSLog(@"Store Configuration Failure\n%@", ([error localizedDescription] != nil) ? [error localizedDescription] : @"Unknown Error");    }    return moContext;}

In the above Code:
1) We created a global managedobjectcontext object mocontext;
2) set the persistent store coordinator to XML, save the file name as coredatatutorial. XML, and put it in the storage path defined earlier.

Okay. Now everything is ready. I only owe it to managedobject! Next we will define this data object class. Add the core data-> nsmanagedobject subclass class to the project, named run (the class name defined by entity in the model ).

Run. h

#import <CoreData/NSManagedObject.h>@interface Run : NSManagedObject{    NSInteger processID;}@property (retain) NSDate *date;@property (retain) NSDate *primitiveDate;@property NSInteger processID;@end

Run. m

////  Run.m//  CoreDataTutorial////  Created by kesalin on 8/29/11.//  Copyright 2011 kesalin@gmail.com. All rights reserved.//#import "Run.h"@implementation Run@dynamic date;@dynamic primitiveDate;- (void) awakeFromInsert{    [super awakeFromInsert];    self.primitiveDate = [NSDate date];}#pragma mark -#pragma mark Getter and setter- (NSInteger)processID {    [self willAccessValueForKey:@"processID"];    NSInteger pid = processID;    [self didAccessValueForKey:@"processID"];    return pid;}- (void)setProcessID:(NSInteger)newProcessID{    [self willChangeValueForKey:@"processID"];    processID = newProcessID;    [self didChangeValueForKey:@"processID"];}// Implement a setNilValueForKey: method. If the key is “processID” then set processID to 0.//- (void)setNilValueForKey:(NSString *)key {        if ([key isEqualToString:@"processID"]) {        self.processID = 0;    }    else {        [super setNilValueForKey:key];    }}@end

Note:
1) The access attribute of date and primitivedate in this class is @ dynamic, which indicates that the corresponding setter and getter will be dynamically generated at runtime;
2) Here we demonstrate how to manually implement the setter and getter of processid: To enable managedobjeccontext to detect processid changes and automatically support Undo/Redo, we need to inform the system when accessing and changing data objects. Will/didaccessvalueforkey and will/didchangevalueforkey play this role.
3) when we set nil to the Data Object processid, we can capture this situation in setnilvalueforkey and set processid to 0;
4) when the data object is inserted into managedobjectcontext, we set the time in awakefrominsert to the current time.

3. Create or read data objects, set their values, and save
Now everything is ready. We can create or read data objects from persistent files, set their values, and save them to persistent files. In this example, the persistent file is an XML file. Modify the code in main () as follows:

int main (int argc, const char * argv[]){    NSLog(@" === Core Data Tutorial ===");    // Enable GC    //    objc_startCollectorThread();    NSError *error = nil;        NSManagedObjectModel *moModel = managedObjectModel();    NSLog(@"The managed object model is defined as follows:\n%@", moModel);        if (applicationLogDirectory() == nil) {        exit(1);    }        NSManagedObjectContext *moContext = managedObjectContext();        // Create an Instance of the Run Entity    //    NSEntityDescription *runEntity = [[moModel entitiesByName] objectForKey:@"Run"];    Run *run = [[Run alloc] initWithEntity:runEntity insertIntoManagedObjectContext:moContext];    NSProcessInfo *processInfo = [NSProcessInfo processInfo];    run.processID = [processInfo processIdentifier];        if (![moContext save: &error]) {        NSLog(@"Error while saving\n%@", ([error localizedDescription] != nil) ? [error localizedDescription] : @"Unknown Error");        exit(1);    }        // Fetching Run Objects    //    NSFetchRequest *request = [[NSFetchRequest alloc] init];    [request setEntity:runEntity];    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:YES];    [request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];        error = nil;    NSArray *array = [moContext executeFetchRequest:request error:&error];    if ((error != nil) || (array == nil))    {        NSLog(@"Error while fetching\n%@", ([error localizedDescription] != nil) ? [error localizedDescription] : @"Unknown Error");        exit(1);    }        // Display the Results    //    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];    [formatter setDateStyle:NSDateFormatterMediumStyle];    [formatter setTimeStyle:NSDateFormatterMediumStyle];        NSLog(@"%@ run history:", [processInfo processName]);        for (run in array)    {        NSLog(@"On %@ as process ID %ld", [formatter stringForObjectValue:run.date], run.processID);    }        return 0;}

In the above Code:
1) first obtain the global nsmanagedobjectmodel and nsmanagedobjectcontext objects: momodel and mocontext;
2) create a run entity and set its property processid to the ID of the current process;
3) Save the data object to the persistent file: [mocontext save: & error]. We don't need to deal with persistentstorecoordinator. We only need to send a save message to managedobjectcontext. nsmanagedobjectcontext transparently processes the read and write of persistent data files;
4) Then we create a fetchrequest to query the data records stored in the persistent data file, and sort the results in ascending order by date. The query operation is also handled by managedobjectcontext: [mocontext
Executefetchrequest: Request error: & error];
5) print the query results;

Success! Compile and run the program as follows:

21:42:47. 556 coredatatutorial [992: 903] coredatatutorial run history: 21:42:47. 557 coredatatutorial [992: 903] On 2011-9-3 09:41:56 as process ID 9402011-09-03 21:42:47. 557 coredatatutorial [992: 903] On 2011-9-3 09:42:16 as process ID 9552011-09-03 21:42:47. 558 coredatatutorial [992: 903] On 2011-9-3 09:42:20 as process ID 9652011-09-03 21:42:47. 558 coredatatutorial [992: 903] On 2011-9-3 09:42:24 as process ID 9782011-09-03 21:42:47. 559 coredatatutorial [992: 903] On 2011-9-3 09:42:47 as process ID 992

Through this example, we can better understand the operating mechanism of core data. In core data, managedobjectcontext is the most common one. It participates in almost all operations on data objects, including Undo/Redo support. The runtime class corresponding to entity is managedobject, we can understand that the abstract data structure entity is embodied by managedobject in the memory, while the perproty data type is embodied by the member attribute of the managedobject class in the memory. Generally, we do not need to use persistentstorecoordinator
As a result, all the read and write operations on data files are done by managedobjectcontext.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.