Cocoa Core Data efficient way to count entities - objective-c

I read much about Core Data.. but what is an efficient way to make a count over an Entity-Type (like SQL can do with SELECT count(1) ...). Now I just solved this task with selecting all with NSFetchedResultsController and getting the count of the NSArray! I am sure this is not the best way...

I don't know whether using NSFetchedResultsController is the most efficient way to accomplish your goal (but it may be). The explicit code to get the count of entity instances is below:
// assuming NSManagedObjectContext *moc
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:entityName inManagedObjectContext:moc]];
[request setIncludesSubentities:NO]; //Omit subentities. Default is YES (i.e. include subentities)
NSError *err;
NSUInteger count = [moc countForFetchRequest:request error:&err];
if(count == NSNotFound) {
//Handle error
}
[request release];

To be clear, you aren't counting entities, but instances of a particular entity. (To literally count the entities, ask the managed object model for the count of its entities.)
To count all the instances of a given entity without fetching all the data, the use -countForFetchRequest:.
For example:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity: [NSEntityDescription entityForName: entityName inManagedObjectContext: context]];
NSError *error = nil;
NSUInteger count = [context countForFetchRequest: request error: &error];
[request release];
return count;

Swift
It is fairly easy to get a count of the total number of instances of an entity in Core Data:
let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "MyEntity")
let count = context.countForFetchRequest(fetchRequest, error: nil)
I tested this in the simulator with a 400,000+ object count and the result was fairly fast (though not instantaneous).

I'll just add that to make it even more efficient... and because its just a count, you don't really need any property value and certainly like one of the code examples above you don't need sub-entities either.
So, the code should be like this:
int entityCount = 0;
NSEntityDescription *entity = [NSEntityDescription entityForName:#"YourEntity" inManagedObjectContext:_managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
[fetchRequest setIncludesPropertyValues:NO];
[fetchRequest setIncludesSubentities:NO];
NSError *error = nil;
NSUInteger count = [_managedObjectContext countForFetchRequest: fetchRequest error: &error];
if(error == nil){
entityCount = count;
}
Hope it helps.

I believe the easiest and the most efficient way to count objects is to set NSFetchRequest result type to NSCountResultType and execute it with NSManagedObjectContext countForFetchRequest:error: method.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:entityName];
fetchRequest.resultType = NSCountResultType;
NSError *fetchError = nil;
NSUInteger itemsCount = [managedObjectContext countForFetchRequest:fetchRequest error:&fetchError];
if (itemsCount == NSNotFound) {
NSLog(#"Fetch error: %#", fetchError);
}
// use itemsCount

I wrote a simple utility method for Swift 3 to fetch the count of the objects.
static func fetchCountFor(entityName: String, predicate: NSPredicate, onMoc moc: NSManagedObjectContext) -> Int {
var count: Int = 0
moc.performAndWait {
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: entityName)
fetchRequest.predicate = predicate
fetchRequest.resultType = NSFetchRequestResultType.countResultType
do {
count = try moc.count(for: fetchRequest)
} catch {
//Assert or handle exception gracefully
}
}
return count
}

It's really just this:
let kBoat = try? yourContainer.viewContext.count(for: NSFetchRequest(entityName: "Boat"))
"Boat" is just the name of the entity from your data model screen:
What is the global yourContainer?
To use core data, at some point in your app, one time only, you simply go
var yourContainer = NSPersistentContainer(name: "stuff")
where "stuff" is simply the name of the data model file.
You'd simply have a singleton for this,
import CoreData
public let core = Core.shared
public final class Core {
static let shared = Core()
var container: NSPersistentContainer!
private init() {
container = NSPersistentContainer(name: "stuff")
container.loadPersistentStores { storeDescription, error in
if let error = error { print("Error loading... \(error)") }
}
}
func saveContext() {
if container.viewContext.hasChanges {
do { try container.viewContext.save()
} catch { print("Error saving... \(error)") }
}
}
}
So from anywhere in the app
core.container
is your container,
So in practice to get the count of any entity, it's just
let k = try? core.container.viewContext.count(for: NSFetchRequest(entityName: "Boat"))

In Swift 3
static func getProductCount() -> Int {
let moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Product")
let count = try! moc.count(for: fetchRequest)
return count
}

If you want to find count for specific predicated fetch, i believe this is the best way:
NSError *err;
NSUInteger count = [context countForFetchRequest:fetch error:&err];
if(count > 0) {
NSLog(#"EXIST");
} else {
NSLog(#"NOT exist");
}

Swift 5 solution:
var viewContext: NSManagedObjectContext!
do {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "insertName")
let count = try viewContext.count(for: fetchRequest)
print("Counted \(count) objects")
}
catch {
print("Error")
}

Related

Objective-C converting to Swift 3.1 getting error 'Any' is not convertible

I'm finally attempting to convert one of my Objective-C apps to Swift 3.1. I'm also taking a tutorial on Swift to help me out. However, I'm running into the following error when trying to convert a 'for in' loop to Swift that worked successfully in Obj-C. I've posted both the Swift and Objective-C code below and commented the line in Swift where I am getting the error. I am getting the error with
for managedObject: NSManagedObject in myResults{
The error states
'Any' is not convertible to 'MSManageObject'
Any help pointing me in the right direction is greatly appreciated.
//IN SWIFT 3.1
let context: NSManagedObjectContext? =
CoreDataHelper.shared().context
let fetchRequest = NSFetchRequest<NSFetchRequestResult>()
let entity = NSEntityDescription.entity(forEntityName:
"Exhibitors", in: context!)
fetchRequest.entity = entity
var myResults : NSArray = try!
CoreDataHelper.shared().context.fetch(fetchRequest) as NSArray
self.objects = myResults as! [Any]
if !(myResults != nil) || !((myResults.count) != nil) {
print("No Exhibitor objects found to be deleted!")
}
else {
//****Getting error 'Any' is not convertible to 'NSManagedObject'
for managedObject: NSManagedObject in myResults {
if !(managedObject.value(forKey: "fav") == "Yes") {
context?.deleteObject(managedObject)
var error: Error? = nil
// Save the object to persistent store
if !context?.save(error) {
print("Can't Save! \(error) \
(error?.localizedDescription)")
}
print("Exhibitor object deleted!")
}
}
}
//IN OBJECTIVE-C
NSManagedObjectContext *context = [[CoreDataHelper sharedHelper]
context];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]
init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Exhibitors" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSArray *myResults = [[[CoreDataHelper sharedHelper]
context] executeFetchRequest:fetchRequest error:nil];
self.objects = myResults;
if (!myResults || !myResults.count){
NSLog(#"No Exhibitor objects found to be deleted!");
}
else{
for (NSManagedObject *managedObject in myResults) {
if (![[managedObject valueForKey:#"fav"]
isEqualToString:#"Yes"]) {
[context deleteObject:managedObject];
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error,
[error localizedDescription]);
}
NSLog(#"Exhibitor object deleted!");
}
}
}
The main issue is that your are annotating worse types than the compiler infers.
Don't do that. Don't annotate types unless the compiler tells you to do.
For example the managed object context is supposed to be non-optional
let context = CoreDataHelper.shared().context
Your fetch returns [NSManagedObject], never use NSArray and never cast distinct types up to more unspecified like [Any]
Simply write
let fetchRequest = NSFetchRequest<NSFetchRequestResult>()
let entity = NSEntityDescription.entity(forEntityName: "Exhibitors", in: context)
fetchRequest.entity = entity
do { // its always recommended to do a good error handling !!
self.objects = try CoreDataHelper.shared().context.fetch(fetchRequest)
for managedObject in self.objects {
...
}
} catch { print(error) }
If objects is empty the loop will be skipped.
Instead of this:
var myResults : NSArray = try! CoreDataHelper.shared().context.fetch(fetchRequest) as NSArray
Do this:
let myResults : [NSManagedObject] = try! CoreDataHelper.shared().context.fetch(fetchRequest)
You should also use less ! operators, as they may crash your app, try using the guard let pattern or ? operators.

Core Data update does not save and does not give any error, why?

I am using a very simple piece of code to update an NSManagedObject, but the save does not make it to the persistent store (SQLite). There are no error messages and the logs look ok so I am a little lost.
I have scaled down the code as much as possible to try and isolate the problem as shown below.
The logs tell me that the orderNumber and status are set correctly and also the debug output of the arrays are all correct, but my simple update still fails without any error at all.
+ (int) synchOrderWithStatusUpdate:(NSString *)orderNumber : (int)status {
if ([NWTillHelper isDebug] == 1) {
NSNumber *statusCheck = [NSNumber numberWithInt:status];
NSLog(#"WebServices:synchOrderWithStatusUpdate:ordernumber = %#, status = %d, status2 = %#", orderNumber, status, statusCheck);
}
synchOrderErrorCode = 0;
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = appDelegate.persistentContainer.viewContext;
// *** The query for all tables uses orderNumber as selection so we set that up first for re use
NSPredicate *predicateOrderNumber =[NSPredicate predicateWithFormat:#"orderNumber like[cd] %#", [NWTillHelper getCurrentOrderNumber]];
NSFetchRequest *fetchRequestOh = [[NSFetchRequest alloc] initWithEntityName:#"OrderHead"];
NSFetchRequest *fetchRequestOrp = [[NSFetchRequest alloc] initWithEntityName:#"OrderRow"];
NSFetchRequest *fetchRequestTender = [[NSFetchRequest alloc] initWithEntityName:#"Tender"];
fetchRequestOh.predicate = predicateOrderNumber;
fetchRequestOrp.predicate = predicateOrderNumber;
fetchRequestTender.predicate = predicateOrderNumber;
fetchRequestOh.resultType = NSDictionaryResultType;
fetchRequestOrp.resultType = NSDictionaryResultType;
fetchRequestTender.resultType = NSDictionaryResultType;
NSError *errorOh = nil;
NSMutableArray *orderHeads = [[context executeFetchRequest:fetchRequestOh error:&errorOh] mutableCopy];
NSError *errorOrp = nil;
NSArray *orderRows = [[context executeFetchRequest:fetchRequestOrp error:&errorOrp] mutableCopy];
NSError *errorTender = nil;
NSArray *tenderRows = [[context executeFetchRequest:fetchRequestTender error:&errorTender] mutableCopy];
if ([NWTillHelper isDebug] == 1) {
NSLog(#"WebServices:synchOrderWithStatusUpdate:orderHeadsArray: %#", [orderHeads objectAtIndex:0]);
NSLog(#"WebServices:synchOrderWithStatusUpdate:orderRowsArray: %#", orderRows);
NSLog(#"WebServices:synchOrderWithStatusUpdate:tenderRowsArray: %#", tenderRows);
}
// *** Set the status before upload since this dictates what will happen in backend
// *** regardless if synch is successful or not
NSManagedObject *orderHeadObject = nil;
orderHeadObject = [orderHeads objectAtIndex:0];
[orderHeadObject setValue:[NSNumber numberWithInt:status] forKey:#"status"];
// Save the objects to persistent store
NSError *error = Nil;
[context save:&error];
NSLog(#"Jongel Error = %#", error);
if(error !=nil) {
if([NWTillHelper isDebug] == 1) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
synchOrderErrorCode = 99;
}
return 10101;
The orderHeads are fetched as dictionaries. The NSManagedObjectContext will not be aware of any changes made to a dictionary. Only NSManagedObjects will be managed by the NSManagedObjectContext, hence the name ;-)
Try to fetch the orderHeadObject as an NSManagedObject as this will allow you to save the changes back into the store. If you need the dictionary for JSON serialisation: Just fetch it again as a dictionary after you have made the changes. That second fetch will be very fast since all values of the object are already cached, so CoreData won't have to reload from the database.

How to NSFetchedResultsController coding in Swift

can't figure out how to rewrite the following method in swift
for a better learning curve, so i tried to translate this code. so lets select a more difficult method to do so. it has error handling, object init and parameter settings, an array of object pointers, selectors, nil, and self..
Objective-C:
-(NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Event" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"timeStamp" ascending:NO];
NSArray *sortDescriptors = #[sortDescriptor];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *frC = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:nil
cacheName:#"Master"];
frC.delegate = self;
self.fetchedResultsController = frC;
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return _fetchedResultsController;
}
specially can't figure out how to call NSEntityDescription *entity.
while interpreting the specs i could not rewrite this correct..
swift:
var fetchedResultsController: NSFetchedResultsController {
var _fetchedResultsController: NSFetchedResultsController? = nil //??
var fetchRequest: NSFetchRequest? = nil // ??
var entity: NSEntityDescription = NSEntityDescription( /*. . .*/ ) //??
fetchRequest.entity(entity) //?? sure this is wrong
...
return _fetchedResultsController
}
This looks like the code you get when you set up a master-detail project with CoreData.
You can do the same, in Xcode 6, but choosing Swift as the language. In MasterViewController, you get :
var fetchedResultsController: NSFetchedResultsController {
if _fetchedResultsController != nil {
return _fetchedResultsController!
}
let fetchRequest = NSFetchRequest()
// Edit the entity name as appropriate.
let entity = NSEntityDescription.entityForName("Event", inManagedObjectContext: self.managedObjectContext)
fetchRequest.entity = entity
// Set the batch size to a suitable number.
fetchRequest.fetchBatchSize = 20
// Edit the sort key as appropriate.
let sortDescriptor = NSSortDescriptor(key: "timeStamp", ascending: false)
let sortDescriptors = [sortDescriptor]
fetchRequest.sortDescriptors = [sortDescriptor]
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext, sectionNameKeyPath: nil, cacheName: "Master")
aFetchedResultsController.delegate = self
_fetchedResultsController = aFetchedResultsController
var error: NSError? = nil
if !_fetchedResultsController!.performFetch(&error) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
//println("Unresolved error \(error), \(error.userInfo)")
abort()
}
return _fetchedResultsController!
}
var _fetchedResultsController: NSFetchedResultsController? = nil
This looks like a line-to-line translation, I hope it helps.
try lazy:
lazy var fetchedResultsController: NSFetchedResultsController = {
let fetchRequest = NSFetchRequest()
// Edit the entity name as appropriate.
let entity = NSEntityDescription.entityForName("Event", inManagedObjectContext: self.managedObjectContext())
fetchRequest.entity = entity
// Set the batch size to a suitable number.
fetchRequest.fetchBatchSize = 20
// Edit the sort key as appropriate.
let sortDescriptor = NSSortDescriptor(key: "timeStamp", ascending: false)
let sortDescriptors = [sortDescriptor]
fetchRequest.sortDescriptors = [sortDescriptor]
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext(), sectionNameKeyPath: nil, cacheName: "Master")
aFetchedResultsController.delegate = self
var error: NSError? = nil
if !aFetchedResultsController.performFetch(&error) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
//println("Unresolved error \(error), \(error.userInfo)")
abort()
}
return aFetchedResultsController
}()

How to update existing object in Core Data?

When I insert new object I do with following code:
NSManagedObjectContext *context = [appDelegate managedObjectContext];
Favorits *favorits = [NSEntityDescription insertNewObjectForEntityForName:#"Favorits" inManagedObjectContext:context];
favorits.title = #"Some title";
NSError *error;
if (![context save:&error]) {
NSLog(#"Whoops");
}
How can I update existing object in core data?
Updating is simple as creating a new one.
To update a specific object you need to set up a NSFetchRequest. This class is equivalent to a SELECT statetement in SQL language.
Here a simple example:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:#"Favorits" inManagedObjectContext:moc]];
NSError *error = nil;
NSArray *results = [moc executeFetchRequest:request error:&error];
// error handling code
The array results contains all the managed objects contained within the sqlite file. If you want to grab a specific object (or more objects) you need to use a predicate with that request. For example:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"title == %#", #"Some Title"];
[request setPredicate:predicate];
In this case results contains the objects where title is equal to Some Title. Setting a predicate is equal to put the WHERE clause in a SQL statement.
For further info I suggest you to read the Core Data programming guide and NSFecthRequest class reference.
Core Data Programming Guide
NSFecthRequest Class Reference
Hope it helps.
EDIT (snippet that can be used to update)
// maybe some check before, to be sure results is not empty
Favorits* favoritsGrabbed = [results objectAtIndex:0];
favoritsGrabbed.title = #"My Title";
// save here the context
or if you are not using a NSManagedObject subclass.
// maybe some check before, to be sure results is not empty
NSManagedObject* favoritsGrabbed = [results objectAtIndex:0];
[favoritsGrabbed setValue:#"My title" forKey:#"title"];
// save here the context
In both cases if you do a save on the context, data will be updated.
You have to fetch the object from the context, change the properties you desire, then save the context as you are in your example.
I hope this will help u. as it works for me.
NSMutableArray *results = [[NSMutableArray alloc]init];
int flag=0;
NSPredicate *pred;
if (self.txtCourseNo.text.length > 0) {
pred = [NSPredicate predicateWithFormat:#"courseno CONTAINS[cd] %#", self.txtCourseNo.text];
flag=1;
} else {
flag=0;
NSLog(#"Enter Corect Course number");
}
if (flag == 1) {
NSLog(#"predicate: %#",pred);
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]initWithEntityName:#"Course"];
[fetchRequest setPredicate:pred];
results = [[self.context executeFetchRequest:fetchRequest error:nil] mutableCopy];
if (results.count > 0) {
NSManagedObject* favoritsGrabbed = [results objectAtIndex:0];
[favoritsGrabbed setValue:self.txtCourseName.text forKey:#"coursename"];
[self.context save:nil];
[self showData];
} else {
NSLog(#"Enter Corect Course number");
}
}
if you are a swift programmer this can help you :
if you want to delete a NSManagedObject
in my case ID is a unique attribute for entity STUDENT
/** for deleting items */
func delete(identifier: String) {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let fetchRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "STUDENT")
let predicate = NSPredicate(format: "ID = '\(identifier)'")
fetchRequest.predicate = predicate
do
{
let object = try context.fetch(fetchRequest)
if object.count == 1
{
let objectDelete = object.first as! NSManagedObject
context.delete(objectDelete)
}
}
catch
{
print(error)
}
}
if you want to update a NSManagedObject :
/** for updating items */
func update(identifier: String,name:String) {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let fetchRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "STUDENT")
let predicate = NSPredicate(format: "ID = '\(identifier)'")
fetchRequest.predicate = predicate
do
{
let object = try context.fetch(fetchRequest)
if object.count == 1
{
let objectUpdate = object.first as! NSManagedObject
objectUpdate.setValue(name, forKey: "name")
do{
try context.save()
}
catch
{
print(error)
}
}
}
catch
{
print(error)
}
}
I saw an answer in Objective-C which helped me. I am posting an answer for Swift users -
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let updateCont = appDelegate?.persistentContainer.viewContext
let pred = NSPredicate(format: "your_Attribute_Name = %#", argumentArray : [your_Arguments])
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "your_Entity_Name")
request.predicate = pred
do {
let resul = try updateCont?.fetch(request) as? [NSManagedObject]
let m = resul?.first
m?.setValue(txtName.text, forKey: "your_Attribute_Name_Whose_Value_Should_Update")
try? updateCont?.save()
} catch let err as NSError {
print(err)
}

Relationship between Entities are not persisting

In my application, I have Category and Sub_Category entities which are having a to-many relation ship between them.
Firstly, when the App runs for the first time the relation attribute(category_subCategory) is working as shown below:
2012-04-11 04:03:39.344 SupplyTrackerApp[27031:12f03] Saved
2012-04-11 04:03:47.423 SupplyTrackerApp[27031:fb03] Category<Category: 0x6ba4e90> (entity: Category; id: 0x6e95620 <x-coredata://00E5784E-D032-41DD-BD60-B85B0BBF8E31/Category/p1> ; data: {
categoryID = 1;
categoryName = Antiques;
"category_SubCategory" = (
"0x6ebb4f0 <x-coredata://00E5784E-D032-41DD-BD60-B85B0BBF8E31/Sub_Category/p1>"
);
catetogoryDescription = "Contains a Sub categories related to Antique pieces";
})
But when I exit the app an restart the application, that relationship does exists. The output looks like this..
2012-04-11 04:05:04.455 SupplyTrackerApp[27038:fb03] In Cell for row at index path
2012-04-11 04:05:05.548 SupplyTrackerApp[27038:fb03] Category<Category: 0x6ecaca0> (entity: Category; id: 0x6eb4ab0 <x-coredata://00E5784E-D032-41DD-BD60-B85B0BBF8E31/Category/p1> ; data: {
categoryID = 1;
categoryName = Antiques;
"category_SubCategory" = "<relationship fault: 0x6ecf0a0 'category_SubCategory'>";
catetogoryDescription = "Contains a Sub categories related to Antique pieces";
})
Here is where I'm calling the create entities..
-(void) loadDataIntoDocument{
NSLog(#"In Load Data");
dispatch_queue_t fetch=dispatch_queue_create("Data Fetcher", NULL);
dispatch_async(fetch, ^{
[Sub_Category createSubCategory:context];
NSError *error;
if (![context save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}else {
NSLog(#"Saved");
}
});
dispatch_release(fetch);
}
So the Sub_Category+Create Category file has the following code.
+(Sub_Category *) createSubCategory:(NSManagedObjectContext *)context{
Sub_Category *subCategory=nil;
NSFetchRequest *request=[NSFetchRequest fetchRequestWithEntityName:#"Sub_Category"];
request.predicate=[NSPredicate predicateWithFormat:#"subCategoryID=%#", #"11"];
NSSortDescriptor *sortDescriptor=[NSSortDescriptor sortDescriptorWithKey:#"subCategoryName" ascending:YES];
request.sortDescriptors=[NSArray arrayWithObject:sortDescriptor];
NSError *error;
NSArray *matches=[context executeFetchRequest:request error:&error];
if (!matches||[matches count]>1) {
///errorrrrrrrrrr
} else if([matches count]==0) {
subCategory=[NSEntityDescription insertNewObjectForEntityForName:#"Sub_Category" inManagedObjectContext:context];
subCategory.subCategoryID=[NSString stringWithFormat:#"%i", 11];
subCategory.subCategoryName=#"Antiquities";
subCategory.subCategoryDescription=#"Contains several products related to antiquities";
subCategory.subCategory_Category =[Category createCategory:context];
}else {
subCategory=[matches lastObject];
}
return subCategory;
}
And then I'm calling the Category+Create Category file which has the following code.
+(Category *) createCategory:(NSManagedObjectContext *)context{
Category *category=nil;
NSFetchRequest *request=[NSFetchRequest fetchRequestWithEntityName:#"Category"];
request.predicate=[NSPredicate predicateWithFormat:#"categoryID=%#", #"1"];
NSSortDescriptor *sortDescriptor=[NSSortDescriptor sortDescriptorWithKey:#"categoryName" ascending:YES];
request.sortDescriptors=[NSArray arrayWithObject:sortDescriptor];
NSError *error;
NSArray *matches=[context executeFetchRequest:request error:&error];
if (!matches||[matches count]>1) {
///errorrrrrrrrrr
} else if([matches count]==0) {
category=[NSEntityDescription insertNewObjectForEntityForName:#"Category" inManagedObjectContext:context];
category.categoryID=[NSString stringWithFormat:#"%d",1];
category.categoryName=#"Antiques";
category.catetogoryDescription=#"Contains a Sub categories related to Antique pieces";
}else {
category=[matches lastObject];
}
return category;
}
Can anyone help me out regarding this..
I'm stuck on this from few days...
I looks like you're using dispatch_async to do the -save: in the background. This is probably violating the "thread confinement" rules for dealing with an NSManagedObject (in short, they should only be used in the thread they were created on. Same applies to any objects fetched from them).
For more information on how to do concurrency with Core Data, see this WWDC Session.
Try only using your Core Data stack (and any objects you fetch from it) from the main thread.