Cocoa Core Data: Setting default entity property values?

别说谁变了你拦得住时间么 提交于 2019-12-08 01:01:56

问题


I know I can set default values either in the datamodel, or in the -awakeFromInsert method of the entity class. For example, to make a "date" property default to the current date:

- (void) awakeFromInsert
{
NSDate *now = [NSDate date];
self.date = now;
}

How though can I make an "idNumber" property default to one greater than the previous object's idNumber?

Thanks, Oli

EDIT: Relevant code for my attempt (now corrected)

- (void) awakeFromInsert
{
self.idNumber = [NSNumber numberWithInt:[self maxIdNumber] + 1];
}

-(int)maxIdNumber{
NSManagedObjectContext *moc = [self managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Flight" inManagedObjectContext:moc];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entityDescription];

// Set example predicate and sort orderings...
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"idNumber > %@", [NSNumber numberWithInt:0]];
[request setPredicate:predicate];

[request setFetchLimit:1];

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"idNumber" ascending:NO];
[request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];

NSError *error;
NSArray *array = [moc executeFetchRequest:request error:&error];
if (array == nil | array.count == 0)
{
    return 0;
} 
return [[[array objectAtIndex:0] valueForKey:@"idNumber"] intValue];
}

If the maxIdNumber method is called, the new object is added to the table twice!? (but with the correct idNumber). The two entries in the table are linked - editing / removing one also edits / removes the other. For this reason I believe it has something to do with the managed object context. For what its worth, the outcome (two copies) is the same no matter how many times the maxIdNumber method is called in the awakFromNib; even if self.idNumber is just set to [NSNumber numberWithInt:5] and the maxIdNumber method is just called for a throwaway variable.

Any clues??


回答1:


SOLVED IT!

Ok, the problem of double entry occurs when a fetch request is performed from within the awakeFromInsert method. Quoting from the docs:

You are typically discouraged from performing fetches within an implementation of awakeFromInsert. Although it is allowed, execution of the fetch request can trigger the sending of internal Core Data notifications which may have unwanted side-effects. For example, on Mac OS X, an instance of NSArrayController may end up inserting a new object into its content array twice.

A way to get around it is to use the perfromSelector:withObject:afterDelay method as outlined here (I am only allowed to post one hyperlink :( ):http://www.cocoabuilder.com/archive/cocoa/232606-auto-incrementing-integer-attribute-in-awakefrominsert.html.

My working code is now as follows: (note, I have put the bulk of the fetching code used above into a category to tidy it up a little, this allows me to use the method fetchObjectsForEntityName:withPredicate:withFetchLimit:withSortDescriptors:)

- (void) awakeFromInsert
{
[self performSelector:@selector(setIdNumber) withObject:nil afterDelay:0];
self.date = [NSDate date];
}


-(void)setIdNumber
{
int num  = 0;

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"idNumber" ascending:NO];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"idNumber > %@", [NSNumber numberWithInt:0]];

NSArray *array = [[self managedObjectContext] fetchObjectsForEntityName:@"Flight" 
                                                          withPredicate:predicate 
                                                         withFetchLimit:0
                                                    withSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];   

if (array != nil & array.count != 0)
{
    num = [[[array objectAtIndex:0] valueForKey:@"idNumber"] intValue]; 
} 

num ++;

[self setIdNumber:[NSNumber numberWithInt:num]];
}

Let me know what you think!




回答2:


One Approach: Create a fetch request of all instances of your entity with a limit of 1, sorted by idNumber to get the highest number.

Another Approach: Keep the highest idNumber in your store's metadata and keep incrementing it.

There are plenty of arguments for and against either. Ultimately, those are the two most common and the choice is yours.




回答3:


An easier way to do that is to override the newObject method of NSArrayController:

- (id) newObject
{
    id result=[super newObject];
    [result setValue: [NSDate date] forKey: @"date"];
    return result;
}


来源:https://stackoverflow.com/questions/3729768/cocoa-core-data-setting-default-entity-property-values

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!