I am having a bit of trouble figuring out this Core Data stuff. How do I create a new entry with a unique ID? In SQL I would just declare one field as an autoincrement fie
Core data is used for persistance framework, this framework abstracts the primary key.
Each NSManagedObject has its own unique key built in which is available in its objectID property.
This id is internally used to link entities over its relations. There is no need to maintain an own id as a primary key as you are used to do in SQL.
You can always get the id by NSManagedObject.objectID. and fetching object context using NSMananagedObjectContext.objectWithId
Though i agree with what you said, there is an ID mechanism behind core data. ID are indeed managed by Core-Data but you can retrieve them with :
NSManagedObjectID *moID = [managedObject objectID];
For more informations see : Core Data Programming Guide
This class function will return next available number for your id property (it must be integer property).
I call it auto-increment value generator. I still agree with others that there is objectID for that but sometimes you just need number.
You can put this function in your NSManagedObject subclass for the entity:
+(NSNumber *)nextAvailble:(NSString *)idKey forEntityName:(NSString *)entityName inContext:(NSManagedObjectContext *)context{
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSManagedObjectContext *moc = context;
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:moc];
[request setEntity:entity];
// [request setFetchLimit:1];
NSArray *propertiesArray = [[NSArray alloc] initWithObjects:idKey, nil];
[request setPropertiesToFetch:propertiesArray];
[propertiesArray release], propertiesArray = nil;
NSSortDescriptor *indexSort = [[NSSortDescriptor alloc] initWithKey:idKey ascending:YES];
NSArray *array = [[NSArray alloc] initWithObjects:indexSort, nil];
[request setSortDescriptors:array];
[array release], array = nil;
[indexSort release], indexSort = nil;
NSError *error = nil;
NSArray *results = [moc executeFetchRequest:request error:&error];
// NSSLog(@"Autoincrement fetch results: %@", results);
NSManagedObject *maxIndexedObject = [results lastObject];
[request release], request = nil;
if (error) {
NSLog(@"Error fetching index: %@\n%@", [error localizedDescription], [error userInfo]);
}
//NSAssert3(error == nil, @"Error fetching index: %@\n%@", [error localizedDescription], [error userInfo]);
NSInteger myIndex = 1;
if (maxIndexedObject) {
myIndex = [[maxIndexedObject valueForKey:idKey] integerValue] + 1;
}
return [NSNumber numberWithInteger:myIndex];
}
Swift 5.0
func nextAvailble(_ idKey: String, forEntityName entityName: String, in context: NSManagedObjectContext) -> NSNumber? {
let req = NSFetchRequest<NSFetchRequestResult>.init(entityName: entityName)
let entity = NSEntityDescription.entity(forEntityName: entityName, in: context)
req.entity = entity
req.fetchLimit = 1
req.propertiesToFetch = [idKey]
let indexSort = NSSortDescriptor.init(key: idKey, ascending: false)
req.sortDescriptors = [indexSort]
do {
let fetchedData = try context.fetch(req)
let firstObject = fetchedData.first as! NSManagedObject
if let foundValue = firstObject.value(forKey: idKey) as? NSNumber {
return NSNumber.init(value: foundValue.intValue + 1)
}
} catch {
print(error)
}
return nil
}
Take a look at NSProcessInfo / ProcessInfo from where we can fetch unique id.
Objective-C code snippet:
[[NSProcessInfo processInfo] globallyUniqueString]
.
Swift code snippet:
let uniqueId = ProcessInfo().globallyUniqueString
print("uniqueId: \(uniqueId)")
Apple Docs:
Global ID for the process. The ID includes the host name, process ID, and a time stamp, which ensures that the ID is unique for the network, which is handy if you don't want people guessing the id.
i think this will be usefull in such conditions.
http://lists.apple.com/archives/cocoa-dev/2006/Jul/msg01801.html We can get maxExistingID . SO we can increment that when saving a new item
Here are three kinds of unique ID representation of CoreData object:
NSManagedObjectID *taskID = [task objectID];
NSURL *taskUniqueURLKey = task.objectID.URIRepresentation;
NSString *taskUniqueStringKey = task.objectID.URIRepresentation.absoluteString;
!!!!Note: if you want to use above unique key as index, please make sure the object is saved to context before using it , or the objectID would be a temporary Id, which will be replaced later (e.g. after saved). See the apple document of NSManagedObjectID class :
- (BOOL)isTemporaryID; // indicates whether or not this ID will be replaced later,
such as after a save operation (temporary IDs are assigned to newly inserted objects
and replaced with permanent IDs when an object is written to a persistent store); most
IDs return NO