I am using core data and have been using code like this:
[self.form setValue:self.comments.text forKey:#"comments"];
I want to put code like this into a loop, all my coredata names are the same as the property name. How can I say forKey:self.comments.name and get the same outcome as above or something like that?
EDIT:
If this is not possible, is there another way to set a ton of values into coredata from properties? I have 50+ attributes and properties alike that need to be set and would like to avoid using what im doing now.
If you really want it, you may use these functions from objc/runtime.h:
objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount) // To get properties declared by a class.
const char *property_getName(objc_property_t property) // To get the name of one property
Something like this:
unsigned int propCount = 0;
objc_property_t *properties = class_copyPropertyList([self class], &propCount);
for(int idx = 0; idx < propCount; idx++) {
objc_property_t prop = *(properties + idx);
NSString *key = #(property_getName(prop));
NSLog(#"%#", key);
}
There really is no substitute for reading the docs on CoreData as the patterns for use and syntax will not be obvious at all without a little legwork.
That said, you typically fetch an instance of your NSManagedObject subclass from the data store:
NSManagedObjectContext* moc = [delegate managedObjectContext];
NSEntityDescription* description = [NSEntityDescription entityForName:#"Filter" inManagedObjectContext:moc];
NSSortDescriptor* descriptor = [NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES];
NSFetchRequest* request = [[NSFetchRequest alloc] init];
[request setEntity:description];
[request setSortDescriptors:[NSArray arrayWithObject:descriptor]];
NSError *error;
_enabledFilters = [NSMutableArray arrayWithArray:[moc executeFetchRequest:request error:&error]];
if (error) {
NSLog(#"%#",error.localizedDescription);
}
In this example I now have an array of instances of my NSManagedObject called "Filter"
Then you can select the appropriate instance to reference, and access all of it's attributes with simple dot syntax.
Filter* thisFilter = (Filter*)[_displayFilters objectAtIndex:indexPath.row];
cell.label.text = thisFilter.name;
cell.label.backgroundColor = [UIColor clearColor];
NSString*targetName = thisFilter.imageName;
UIImage *image = [UIImage imageNamed:targetName];
cell.image.image = image;
Now I've taken info from my persistent data store, and used it within my app.
Going the other way and writing to an instance within your data store is only slightly different, in that you directly set the attributes of an instance of your NSManagedObject subclass, and then call save on the context to push any changes down to the store.
TL;DR - you owe it to yourself to spend an hour or two with the CoreData docs...
One way would be to declare an array of the attributes yourself.
NSArray *attributes = [NSArray arrayWithObjects:..., #"comments", .., nil]; // or a NSSet
for(NSString *attribute in attributes){
NSString *text = [[self performSelector:NSSelectorFromString(attribute)] text]; // presuming that it's safe to call 'text' on all your properties
[self.form setValue:text forKey:attribute];
}
Or you can use this if you want all the attributes of your core data model.
Related
I perform a fetch from core data of nsmanaged objects. One of the attributes of the managed objects is an NSNumber, corresponding to the id of the objects (not Apple's objectid, my own sequential NSNumber id scheme). For a given object which has an id#, I would like to get the index of that object in the array. However, I can't figure out a way to get a list of the id#s as valueforkey does not work for nsnumbers and objectforkey throws an error with an nsmutablearray. Can anyone suggest how to do this?
Here is my non-working code. The problem is that I can't get a valid list of ids out of the fetched objects.
//FETCH ITEMS
- (id) getItems{
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"Items"];
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:#"lasttouched" ascending:NO];
[fetchRequest setSortDescriptors:#[sort]];
NSError *error = nil;
self.managedObjectContext = [IDModel sharedInstance].managedObjectContext;
NSArray *results = [self.managedObjectContext executeFetchRequest:fetchRequest
NSMutableArray *mutableresults = [results mutableCopy];
[mutableresults removeObjectIdenticalTo:[NSNull null]];
NSArray*someids =[[mutableresults valueForKey:#"myid"] mutableCopy];
//THIS IS EMPTY WHEN LOGGED
_someids = someids;//save to ivar
return mutableresults; //an array of activity objects with all their properties
}
// In method to get index of the object
NSInteger myIndex=[_someids indexOfObject:#33];
NSLog(#"anIndex%ld",(long)anIndex);
You need to remap the objects into a new array. For straight forward something like:
NSMutableArray *arrayOfIdentifiers = [[NSMutableArray alloc] init];
for(WhateverMyManagedObjectIs *item in results) { if(item.myid) [arrayOfIdentifiers addObject:item.myid]; }
This will result in array of ids as NSNumber objects only. Since NSNumber is an object the indexOfObject may not work. The reason is that it will compare pointers instead of values. So you will need to use compare method like:
NSInteger index = -1;
for(NSInteger i=0; i<_someids.count; i++) {
if([_someids[i] compare:#33] == NSOrderedSame) {
index = i;
break; // Break after first one is found
}
}
So in the end it is pretty much the same if you skip mapping your objects and simply compare it on the same object array:
NSInteger index = -1;
for(NSInteger i=0; i<results.count; i++) {
if([[results[i] myid] compare:#33] == NSOrderedSame) {
index = i;
break; // Break after first one is found
}
}
I have this piece of code inside my viewDidLoad method to check the name of the section from the UITableView. What I need is a way to make a similar loop inside the same method to be able to know an attribute value from all stored objects. The Core Data entity is defined in a NSManagedObject subclass called ToDoItem.
for(int i = 0; i < [[self.fetchedResultsController sections] count]; i++)
{
id <NSFetchedResultsSectionInfo> theSection = [[self.fetchedResultsController sections]objectAtIndex:i];
NSString *sectionName = [theSection name];
if ([sectionName isEqualToString:#"0"])
{
haySeccion0 = #"si";
}
}
My suggestion for you is:
fetch only what you need:
NSManagedObjectContext* context = [[NSManagedObjectContext alloc] init] //or use your current context;
context.persistentStoreCoordinator = //Get the coordinator
NSExpressionDescription* objectIdDesc = [NSExpressionDescription new];
objectIdDesc.name = #"objectID";
objectIdDesc.expression = [NSExpression expressionForEvaluatedObject];
objectIdDesc.expressionResultType = NSObjectIDAttributeType;
NSFetchRequest* r = [NSFetchRequest fetchRequestWithEntityName:#"EntityName"];
[r setResultType:NSDictionaryResultType];
[r setPropertiesToFetch:#[objectIdDesc,#"borrar"]];
[r setPredicate:[NSPredicate predicateWithFormat:#"has0Section = %#",#"si"]];
NSError* error = nil;
NSArray* results = [context executeFetchRequest:r error:&error];
//Error handling ...
results will now contain all objects (as dictionaries) on section 0 and their borrar property, perform whatever logic you like on that.
You can perform this code in the background and set the map to some private variable of your view controller (synchronise on some lock when needed).
It sounds like you want to check all the objects then perform an action on a section based on an attribute being on an object.
Why not enumerate all objects, then use indexPathForObject to retrieve the section.
It isn't clear why you need to do this section by section..
I have two entities, one called InProject that has several attributes and one relationship. the relationship is with another entity called Ins.
I am editing one of the Ins that is related to InProject. I used InProject attribute ID which then returns a NSDictionary value that has several key-values one of which is for an array of Ins. I then find the Ins I need to edit in a for loop I edit them, but then I become unstuck because I am not sure how to save the contect of InProject with the *updated Ins
I need to figure out how to save InProject after I have overwritten the Ins attributes I need to update.
This is what my code looks like after battling this problem:
- (void)editSelectedins:(NSString *)projIDString UpdatedNSD:(NSMutableDictionary *)updatedNSD DPC:(int)dpc{
// get context
NSManagedObjectContext *context = [self managedObjectContext];
if (context == nil) {
NSLog(#"Nil");
}
else {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"InsProject" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSError *error;
NSMutableArray *InsProjectDictionaryArray = [[NSMutableArray alloc] init];
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
for (InsProject *insProj in fetchedObjects) {
NSMutableDictionary *tempInsProjectDictionaryArray = [[ NSMutableDictionary alloc] init];
[tempInsProjectDictionaryArray setObject:insProj.companyName forKey:#"CompanyName"];
[tempInsProjectDictionaryArray setObject:insProj.projNo forKey:#"ProjNo"];
[tempInsProjectDictionaryArray setObject:insProj.desc forKey:#"Desc"];
[tempInsProjectDictionaryArray setObject:insProj.guid forKey:#"GUID"];
[tempInsProjectDictionaryArray setObject:insProj.projID forKey:#"ProjID"];
[tempInsProjectDictionaryArray setObject:insProj.ins forKey:#"ins"];
[InsProjectDictionaryArray addObject:tempInsProjectDictionaryArray];
}
// now that you have the InsProjects, choose the one you are curently working on in insView using the projectID
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ProjID==%#",projIDString];
[fetchRequest setPredicate:predicate];
// new array with one value that was created using the NSPredicate ProjID
NSArray *tempInsProjectArray = [InsProjectDictionaryArray filteredArrayUsingPredicate:predicate];
// get ins array out of the NSDictionary to edit
NSSet *inssForInsProject = tempInsProjectArray[0][#"ins"];
NSMutableArray *tempAllinss = [[NSMutableArray alloc] init]; // this will contain everything, that means all repeated values are included
for (Items* currItem in [inssForInsProject allObjects]) {
NSArray *keys = [[[currItem entity] attributesByName] allKeys];
NSDictionary *dict = [currItem dictionaryWithValuesForKeys:keys];
[tempAllinss addObject:dict];
}
NSArray *myArray = [tempAllinss copy];
// get the correct items from myArray anything whos dpc matches the dpc parameter of this method
NSMutableArray *editedinsArray = [[NSMutableArray alloc] init];
for (int i = 0; i < [myArray count]; i++) {
NSMutableDictionary *tempinssDictionary = [myArray objectAtIndex:i];
// if you get a match put it into the new editedinsArray to be edited
if ([[tempinssDictionary objectForKey:#"dpc"] integerValue] == dpc) {
[editedinsArray addObject:tempinssDictionary];
}
}
// by now you should have three things
// 1, access to your ins coredata object //this s wrong I actually have access to insProject
// 2, the values you need to be edited saved into a NSArray (editedinsArray, which will be used to check against and keep old values correct)
// 3, UpdatedNSD which will be used to update any values that need to be updated.
// go through your values and update the ins object
int i = 0;
for (ins *temp in editedinsArray) {
NSDictionary *currentEditedins = [editedinsArray objectAtIndex:i];
i++;
// these values should stay the same so use currentEditedins which contains old vals
NSString *stringToNumberDpc = [currentEditedins valueForKey:#"dpc"];
int tempDpcNum = [stringToNumberDpc integerValue];
NSNumber *dpcNumber = [NSNumber numberWithInt:tempDpcNum];
temp.dpc = dpcNumber;
NSString *totDQtyString = [currentEditedins valueForKey:#"totDQty"];
if ((NSNull *)totDQtyString == [NSNull null]) {
temp.totDQty = #"";
} else {
temp.totDQty = totDQtyString;
}
NSString *totShipString = [currentEditedins valueForKey:#"totShip"];
if ((NSNull *)totShipString == [NSNull null]) {
temp.totShip = #"";
} else {
temp.totShip = totShipString;
}
// values to be updated so use updatedNSD wthich was passed in as method param with the new vals
temp.newInsComp = [updatedNSD valueForKey:#"newInsComp"];
temp.newDryComp = [updatedNSD valueForKey:#"newDryComp"];
temp.updatedRow = [updatedNSD valueForKey:#"updatedRow"];
}
#warning --- I have no idea what to do here... i.e. how do I update the tempInsProjectArray.ins values I have just updated in the above for loop then save context which I hope would update insProj and the ins entities involved.
//save
[context save:&error];
}
}
As you can see at the bottom of the code with #warning I explain where I am having the issue. if I log temp inside the for loop I see the updated values perfectly the issue I am having is how do I then update the current tempInsProjectArray.ins values that I have just edited? then save them of course.
Your code is in great need of simplification. Some ground rules:
Use names with smallInitial and camelCase for variables. So not InsProjectDictionaryArray but insProjectDictionaryArray.
The same applies to dictionary keys indicating attribute names of managed objects. So projNo, not ProjNo.
Avoid cryptic abbreviations. Use plain and readable English Not projNo but projectNumber. What is an Ins? What is "dcp"?
Don't use the plural form for entity names. An suitable name for an item is Item, not Items
Don't use the mutable versions of dictionary and array when immutable ones would do.
Avoid duplicating your data, such as in [array copy].
Avoid dictionaries when you have an object graph. The object graph is what core data creates. It renders dictionaries with values and keys unnecessary.
Don't use IDs. The object graph renders those unnecessary as well in most cases. If you use IDs, do not use strings but numbers, such as long ints, or the object version NSNumber.
When fetching data from the Core Data persistent store, don't fetch all the data and the filter the result. Fetch only the data you need.
What you want to accomplish can surely be done in a few lines of code. I will try to summarize what you want to do as far as I understand it.
Your data model looks something like this:
Project <----->> Item
Where the items are in a to-many relationship called ins. I will rename this items. I will also assume that you will refactor your IDs to be of type NSNumber.
All the code up to myArray could be substituted with this:
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:"Project"];
request.predicate = [NSPredicate predicateWithFormat:#"projectID = %#", projectID];
request.fetchLimit = 1;
NSArray *fetchedObjects = [self.managedObjectContext
executeFetchRequest:request error:nil];
Project *project = fetchedObjects[0];
You now have all items available simply with project.items. I understand that there could be more than one item with a mysterious attribute dcp of type int (i.e. NSNumber for managed objects), that is equal to the dcp parameter passed.
NSSet *matchingItems = [project.items filteredSetUsingPredicate:
[NSPredicate predicateWithFormat:#"dcp = %#", #(dcp)]];
Now it becomes a bit murky. Why do you have type ins in your for loop if the ins are actually of type Item? You then cast them into a dictionary... This should generate a compiler error. Or you have another class called ins instead of Ins??
Anyway, if you stay with the Items you can just update the values with what you pass in your dictionary:
for (Item *item in matchingItems) {
item.newInsComp = [updatedNSD valueForKey:#"newInsComp"];
item.newDryComp = [updatedNSD valueForKey:#"newDryComp"];
item.updatedRow = [updatedNSD valueForKey:#"updatedRow"];
}
[self.managedObjectContext save:nil];
Done!
BTW you could make it even shorter by setting the entity name of the fetch request to "Item" and setting the following predicate:
[NSPredicate predicateWithFormat:#"project.projectID = %# && dcp = %#",
projectID, #(dcp)];
If you know your InProject, then updating your Ins related to that project is a matter of editing property values on your managed objects.
Why not use the predicate to get an NSManagedObject of the InProject, then pull the relationship off of that and edit the values?
NSManagedObjectContext *context = [self managedObjectContext];
if (!context) {
return;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"InsProject" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
// Set the predicate on the Core Data fetch request instead
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"ProjID==%#",projIDString];
NSError *error;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
// We now have an array that has objects matching the projectIdString
// Might want to do some additional checks if you're only expecting zero or one objects
InsProject *aProject = [fetchedObjects lastObject];
// If we have no project, no point going any further
if ( !aProject ) return;
// On this NSManagedObject is an NSSet property with all related Ins objects
for ( Ins *anIns in aProject.ins ) {
// If our Ins item matches the passed dpc...
if ( [ins.dpc integerValue] == dpc ) {
// ...we have a match, edit properties
ins.dpc = #(dpc);
ins.newInsComp = [updatedNSD valueForKey:#"newInsComp"];
ins.newDryComp = [updatedNSD valueForKey:#"newDryComp"];
ins.updatedRow = [updatedNSD valueForKey:#"updatedRow"];
}
}
// These are managed objects, so saving the context saves all the changes
NSError *saveError;
[context save:&saveError];
if ( saveError ) {
NSLog(#"Save error: %#", [error localizedDescription]);
}
I am learning how to use Core Data. I have an app that fills out all the variable of an entity labeled User. I then take these users and load them to a table. At this point the users can be selected and pushed to a new view controller at which point I generate a PDF file of the user selected. So I think I am misunderstanding what it is I have to pass to the view controller for it to access the core data selected in the table. Here is what I have in my table view controller.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.spinner startAnimating];
ReportPDFViewController *reviewViewController = [[ReportPDFViewController alloc] init];
reviewViewController.userInfo = [[self.fetchedResultsController fetchedObjects] objectAtIndex:indexPath.row];
[self.navigationController pushViewController:reviewViewController animated:YES];
}
Then the next view states this
- (void)viewDidLoad
{
[super viewDidLoad];
UIBarButtonItem *barButton = [[UIBarButtonItem alloc] initWithTitle:#"Email PDF"
style:UIBarButtonItemStylePlain
target:self
action:#selector(emailPDF)];
self.navigationItem.rightBarButtonItem = barButton;
TrafficSignalProAppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
context = [appDelegate managedObjectContext];
// Do any additional setup after loading the view.
NSEntityDescription *entitydesc = [NSEntityDescription entityForName:#"User" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entitydesc];
NSError *error;
NSArray *matchingData = [userInfo executeFetchRequest:request error:&error];
NSString *Intersection;
NSString *currentDay;
for (NSManagedObject *obj in matchingData) {
Intersection = sendIntersection;
currentDay = sendDate;
}
NSString* fileName = [self getPDFFileName];
[PDFRenderer drawPDF:fileName intersectionSearch:Intersection dateSearch:currentDay];
[self showPDFFile];
self.navigationItem.title = #"Report";
}
So I'm trying to pass the NSManagedObjectContext of the selected row to then load. I am really lost after that. I'm not sure if passing the managed object context is right and if it is I don't know what is wrong with the code in the ReportPDFViewController. I have looked through all the tutorials I can find. I have a limited programming background so any help would be greatly appreciated.
reviewViewController.userInfo = [[self.fetchedResultsController fetchedObjects] objectAtIndex:indexPath.row];
This sets userInfo to an object of type NSManagedObject (or a subclass).
NSArray *matchingData = [userInfo executeFetchRequest:request error:&error];
This is using userInfo as if it's a NSManagedObjectContext. I would imagine you get an invalid selector error here.
What is the actual type of the userInfo attribute? It should be NSManagedObject.
You do not need to do a fetch request in your viewDidLoad. Core Data is not a database. You do not always need to do a fetch request every time you want some information. Once you already have a managed object, you can get information related to it without a fetch request. If you've set up a custom class for it, you can treat it almost like it's an regular objective-C object.
for (NSManagedObject *obj in matchingData) {
Intersection = sendIntersection;
currentDay = sendDate;
}
This code just doesn't make sense. You're looping, but each time through you're assigning the same value to the variables. I don't know what that value is, since sendIntersection and sendDate are not referred to anywhere else in the code you posted. In any case you're not using the results of the fetch request at all.
I'm going to make a wild guess at what you need to do:
Intersection = [userInfo valueForKey:#"intersection"];
currentDay = [userInfo valueForKey:#"date"];
It's a total guess, because I don't know what your data model is. No loop is needed, since you only want and have one user object.
I have one to many mapping relation with name match and innings.
match <-->> innings
match has fields name, id etc.
innings has fields number.
I am able to get match properties. I create a new match in MatchList in TableListController. I see the data for Match and innings is available in the table. Now, I click the row that was created in the table.
But when I do [match matchinnings], I get a NSSet* inningSet. I am able to get two objects inningA and inningB from inningSet. When I try call [inningA number], I get an error.
Below is my NSFetchResultsController method:
- (NSFetchedResultsController *)fetchedResultsController {
// Set up the fetched results controller if needed.
//NSLog(#"Inside fetchResultsController ");
if (fetchedResultsController == nil) {
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setReturnsObjectsAsFaults:NO];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Match" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setRelationshipKeyPathsForPrefetching:[NSArray arrayWithObject:#"matchinnings"]];
[fetchRequest setIncludesSubentities:YES];
[fetchRequest setResultType:NSManagedObjectResultType];
//[fetchRequest setPropertiesToFetch:[NSArray arrayWithObjects:#"matchinnings.number", nil]];
//[fetchRequest valueForKeyPath:#"matchinnings.number"];
//[fetchRequest setPropertiesToFetch:[NSArray arrayWithObjects:#"matchinnings", #"number", nil]];
//[fetchRequest setRelationshipKeyPathsForPrefetching:[NSArray arrayWithObject:#"matchinnings.number"]];
//[fetchRequest setRelationshipKeyPathsForPrefetching:[NSArray arrayWithObjects:#"matchinnings", #"matchinnings.number", nil]];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"date" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:#"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
}
return fetchedResultsController;
}
In my class MatchContextMO, I get a I get error a EXC_BAD_ACCESS on the line:
inningsArray = [newSet allObjects];
...in this method:
-(NSArray *)determineInningsOrder {
NSArray* array = nil;
NSSet *newSet = [self.match valueForKey:#"matchinnings"];
NSLog(#"Size of set %d", [newSet count]);
NSArray *inningsArray = nil;
#try {
inningsArray = [newSet allObjects];
}
#catch (NSException *exception) {
NSLog(#"Exception in matchinnings %#", [exception reason]);
}
Innings *inningA = [inningsArray objectAtIndex:0];
Innings *inningB = [inningsArray objectAtIndex:1];
if ([inningA isKindOfClass:Innings.class])
NSLog(#"inningA is of type Innings");
Innings* temp;
NSNumber *numberA = [inningA valueForKey:#"number"];
NSLog(#"numberA %d", [numberA intValue]);
if ([numberA intValue] == 2) {
temp = inningA;
inningA = inningB;
inningB = temp;
}
array = [NSArray arrayWithObjects:inningA, inningB, nil];
return array;
}
I am trying to figure it out for last one week. It looks more like CoreData faults.
Your help is greatly appreciated.
I tried iterating over the set returned. Still got a 'EXC_BAD_ACCESS' error on line [a addObject:inningsObject]. NSLog size of set says 2 though.
-(NSArray *)determineInningsOrder {
NSArray* array = nil;
if (!self.match) {
NSLog(#"Match is null");
return nil;
}
NSMutableSet *newSet = [self.match valueForKey:#"matchinnings"];
NSLog(#"Size of set %d", [newSet count]);
//NSSet *inningsSet = [self.match matchinnings];
NSArray *inningsArray = nil;
NSEnumerator *fastEnumerator = [newSet objectEnumerator];
id inningsObject;
NSMutableArray *a = [[NSMutableArray alloc] initWithCapacity:[newSet count]];
while ((inningsObject = [fastEnumerator nextObject])) {
[a addObject:inningsObject];
}
Innings *inningA = [a objectAtIndex:0];
Innings *inningB = [a objectAtIndex:1];
[a release];
if ([inningA isKindOfClass:Innings.class])
NSLog(#"inningA is of type Innings");
NSNumber *numberA = [inningA valueForKey:#"number"];
NSLog(#"numberA %d", [numberA intValue]);
if ([numberA intValue] == 2) {
temp = inningA;
inningA = inningB;
inningB = temp;
}
array = [NSArray arrayWithObjects:inningA, inningB, nil];
return array;
}
Of course if you model something in CoreData as an Integer and provide a custom class to implement it. The attribute is an object: NSNumber.
Example:
.h:
// attributes
#property (nonatomic, retain) NSNumber *version;
// derived attributes
#property (nonatomic, readonly) NSInteger versionIntegerValue;
#property (nonatomic, readonly) NSString *versionStringValue;
.m:
#dynamic version;
- (NSInteger)versionIntegerValue {
return [self.version integerValue];
}
- (NSString *)versionStringValue {
return [NSString stringWithFormat:#"v%d", [self.version integerValue]];
}
What is the object type of inningA or inningB?
Ensure that:
The class has a 'number' property defined
The object model has a 'number' property defined
If those are all correct, please reformat your question so we can read it easier.
Also be more clear as to where you are calling the bottom function? And provide the rest of MatchContectMO. I'm not sure what it is? Is it the MO definition? Or is there something that contains an MO? (The name is not at all clear).
If matchinnings key is the name for a to-many relationship then then:
[self.match valueForKey:#"matchinnings"];
... will return not an NSSet but an NSMutableSet. When you assign it to a NSSet like so:
NSSet *newSet = [self.match valueForKey:#"matchinnings"];
it can lead to problems if you forget and try to change anything.
However, in this case, that is probably not the issue. More likely, you are not getting a set returned at all. I would confirm you are getting a NSMutableSet returned.
I can tell you will absolute certainty that this problem is not being caused by faults. Firstly, you explicitly don't fetch as faults and secondly it is impossible for a fault to cause this kind of problem. Whenever an attribute of a fault represent object is accessed, the full object is read-in (faulted-in in the jargon.) Faults never trigger issues related to attribute access.
You are using a cache. This comes with all sorts of issues. I have read the docs many many times and I'm still not sure when it's refreshed. Try changing the cache to nil. It may be that one of the objects in the cache is no longer in the store and it's trying to access it.
Also get rid of these lines. They are not useful at this stage, and by the looks of your program won't be useful:
[fetchRequest setRelationshipKeyPathsForPrefetching:[NSArray arrayWithObject:#"matchinnings"]];
[fetchRequest setIncludesSubentities:YES];
[fetchRequest setResultType:NSManagedObjectResultType];
Where is the managedObjectContext created? Is it in the same thread that you are running this code? Does it still have a retain count? Try NSLog(#"MOC Retain count: %i", [managedObjectContext retainCount]); If it's not in the same thread make sure that it is. It's not thread safe and you will get these errors if it's not.
How are you setting match? It's not clear from your code. The NSFetchedResultsController is useful for populating a table view, yet match is a property. How is it set? Is NSFetchedResultsController the correct interface to use? Would a normal fetch work as well?
If none of these work I think it's best that you post the contents of the entire file here. As others have said, what's there is right, and it is very hard to diagnose something that we can't see.
It's a little difficult to tell without some more of your implementation, but I would take a look at:
The managedObjectContext object, the managed objects share there lifetime with their owning context
Threading: Make sure you are accessing the objects and using their owning managed context on the same thread
It's a bad idea to give properties names like "number" or "text" or "description", unless you are deliberately subclassing. Core Data actually gives a warning when you try the last, but it doesn't do so with all reserved words. From the NSPropertyDescription Class Reference:
Note that a property name cannot be the same as any no-parameter method name of NSObject or NSManagedObject. For example, you cannot give a property the name "description". There are hundreds of methods on NSObject which may conflict with property names—and this list can grow without warning from frameworks or other libraries. You should avoid very general words (like "font”, and “color”) and words or phrases which overlap with Cocoa paradigms (such as “isEditing” and “objectSpecifier”).
Using valueForKey: consistently, most of the time circumnavigates this problem, but as soon as you make a call like [inningA number], you get an error.
I'm having the same issue, EXC_BAD_ACCESS when I access a one-to-many relationship's count when the containing objects are in a Fault state.
myObject.oneToManyRelationshipProperty.count; <- EXC_BAD_ACCESS
This seems to be fixed by setting relationshipKeyPathsForPrefetching during the Fetch Request, which will "pre-load" the relationship objects during the initial fetch and not fault.
NSFetchRequest *fetchRequest = ...
fetchRequest.relationshipKeyPathsForPrefetching = #[#"yourProperty"];
Feedback on this solution appreciated. I don't understand why I'm getting the bad access; shouldn't access of a Fault simply load the object (and not crash)?