Recover NSEntityDescription from keypath - core-data

Suppose I have core data entities A and B, where B points to A via attribute a.
Given the NSEntityDescription for B, and a key path to a given property of A (e.g #"a.name"), is there any way to recover the NSEntityDescription of A?
Thanks,
Tim

I've managed to to this by parsing the key path myself:
// Split the path to the section name up
NSArray *keyNameParts = [sectionNameKeyPath componentsSeparatedByString:#"."];
// Follow this back to the Entity description for the Section Entity
for (int idx = 0; idx < keyNameParts.count - 1; idx++) {
NSDictionary *relationships = entityDescription.relationshipsByName;
NSString *partName = [keyNameParts objectAtIndex:idx];
NSRelationshipDescription *relationshipDescription = [relationships objectForKey:partName];
if (!relationshipDescription)
{
[NSException raise:#"Relationship not found for keypath"
format:#"Entity '%#' does not point to a relationshop for '%#' in keypath '#'.", entityName, partName, sectionNameKeyPath];
}
entityDescription = relationshipDescription.entity;
}
If there's a more direct method I'd love to know it.

Related

get all attributes for entity from core data

how does my fetchedResultsController method look like, if I want to fetch all my attributes for an entity from core data? I only know and understand how to fetch data for a tableView and I think that is where all my confusion is coming from.
Here is my Core-Data setup:
I'm trying to fill an array with all the Attributes my Setting entity has and the show those values via NSLog output in my debug console.
Here is what I changed so far:
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *newEntry = [NSEntityDescription insertNewObjectForEntityForName:#"Setting" inManagedObjectContext:context];
//NSManagedObject *newSetting = [NSEntityDescription insertNewObjectForEntityForName:#"Setting" inManagedObjectContext:context];
[newEntry setValue: #"StudiSoft" forKey:#"settingName"];
if (_overrideSysTimeSwitch.on) {
[newEntry setValue: #YES forKey:#"settingSysTimeOverride"];
//editSetting.settingSysTimeOverride = #YES;
NSLog(#"IF A");
} else {
//[newEntry setValue: #NO forKey:#"settingSysTimeOverride"];
//editSetting.settingSysTimeOverride = #NO;
NSLog(#"IF B");
}
if (_timeFormatSwitch.on) {
//[newEntry setValue: #YES forKey:#"settingTimeFormat"];
//editSetting.settingTimeFormat = #YES;
NSLog(#"IF C");
} else {
//[newEntry setValue: #NO forKey:#"settingTimeFormat"];
//editSetting.settingTimeFormat = #NO;
NSLog(#"IF D");
}
[self.settingsArray addObject:#"StudiSoft"];
NSError *error;
[context save:&error];
I'm using this code-snipped that and I'm able to modify the core data content.
However, every time I run this code, it of course adds a new object.
I've been looking for a way to update existing Attributes in my Entity, or modify them, but I could NOT find them.
Anyhow this is a good step into the right direction.
I created a completely new project, with just one view, once I have it working on the main view I'm going to experiment with segues....
But for now, how would I update or change existing attributes?
Thanks guys!!
This is my editSave Method to store some data in core data:
- (IBAction)editSave:(UIBarButtonItem *)sender
{
if ([_editSaveButton.title isEqualToString:#"Edit"])
{
[self setTitle:#"Edit Settings"];
//self.title = #"Edit Settings";
_overrideSysTimeSwitch.userInteractionEnabled = YES;
_timeFormatSwitch.userInteractionEnabled = YES;
_editSaveButton.title = #"Save";
} else if ([_editSaveButton.title isEqualToString:#"Save"])
{
[self setTitle:#"Settings"];
//self.title = #"Settings";
_overrideSysTimeSwitch.userInteractionEnabled = NO;
_timeFormatSwitch.userInteractionEnabled = NO;
_editSaveButton.title = #"Edit";
// #############################################################
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
//NSManagedObject *newEntry = [NSEntityDescription insertNewObjectForEntityForName:#"Setting" inManagedObjectContext:context];
//[newEntry setValue: #"StudiSoft" forKey:#"settingName"];
/*NSString *firstName = [anEmployee firstName];
Employee *manager = anEmployee.manager;
Setting *newSetting = [NSString #"Test"];
[newSetting setValue:#"Stig" forKey:#"settingName"];
[aDepartment setValue:[NSNumber numberWithInteger:100000] forKeyPath:#"manager.salary"];*/
//editSetting.settingName = #"Test";
if (_overrideSysTimeSwitch.on) {
//[newEntry setValue: #YES forKey:#"settingSysTimeOverride"];
editSetting.settingSysTimeOverride = #YES;
NSLog(#"IF A");
} else {
//[newEntry setValue: #NO forKey:#"settingSysTimeOverride"];
editSetting.settingSysTimeOverride = #NO;
NSLog(#"IF B");
}
if (_timeFormatSwitch.on) {
//[newEntry setValue: #YES forKey:#"settingTimeFormat"];
editSetting.settingTimeFormat = #YES;
NSLog(#"IF C");
} else {
//[newEntry setValue: #NO forKey:#"settingTimeFormat"];
editSetting.settingTimeFormat = #NO;
NSLog(#"IF D");
}
//[self.settingsArray addObject:#"StudiSoft"];
NSError *error = nil;
//if ([self.managedObjectContext hasChanges]) {
//NSLog(#"SAVE & DISMISS conetx has changed");
if (![context save:&error]) { // save failed
NSLog(#"Save failed: %#", [error localizedDescription]);
} else { // save succeeded
NSLog(#"Save Succeeded");
}
//}
//[self.tableView reloadData];
// #############################################################
}
}
Debug Output:
2014-06-10 19:09:29.881 SettingsCoreData[508:60b] Entry #5: <Setting: 0x8f983e0> (entity: Setting; id: 0x8f97030 <x-coredata://FA78AB86-3225-4B1E-97DD-3F31F5323A18/Setting/p6> ; data: {
settingName = StudiSoft;
settingSysTimeOverride = 0;
settingTimeFormat = 0;
})
2014-06-10 19:09:29.883 SettingsCoreData[508:60b] Entry #6: <Setting: 0x8f98430> (entity: Setting; id: 0x8f97040 <x-coredata://FA78AB86-3225-4B1E-97DD-3F31F5323A18/Setting/p7> ; data: {
settingName = StudiSoft;
settingSysTimeOverride = 1;
settingTimeFormat = 1;
})
Now I should be able to use something like this in my viewDidLoad, right?
if (editSetting.settingSysTimeOverride.boolValue == 0) {
_overrideSysTimeSwitch.on = NO;
} else {
_overrideSysTimeSwitch.on = YES;
}
But it doesn't work as I thought it will :-(
Next you need to call -performFetch: on the NSFetchedResultsController. Make sure you check the response and handle the error if the response is NO.
From there your NSFetchedResultsController is populated and ready to be used. You can then grab individual elements via -objectAtIndex: or you can grab them all with -fetchedObjects.
I would suggest just reviewing the documentation on the methods that are available as it has pretty strong and clear documentation.
Update
If you are not receiving any data then break it down. Take the NSFetchRequest that you created and call -executeFetchRequest:error: against your NSManagedObjectContext and see if you get any data back.
If you do then there is something wrong with your handling of the NSFetchedResultsController.
If you don't then there is something wrong with your NSFetchRequest or you don't have any data in your store.
Update
Sounds like you need to read a book on how Core Data works.
A NSFetchRequest is a query against Core Data so that objects can be returned from the store. You can pass a NSFetchRequest to a NSFetchedResultsController so that the NSFetchedResultsController can monitor the store for changes and let your view controller know when those changes occur.
A NSFetchRequest can also be executed directly against the NSManagedObjectContext and you can retrieve the results directly. You do that by calling -executeFetchRequest:error: against your NSManagedObjectContext and getting a NSArray back. You can then check that NSArray to see if you get any results.
If you do not understand that paragraph then you need to take a step back and read the tutorials on Core Data and/or read a book on Core Data. I can recommend an excellent book on the subject ;-)

How to force create new match in GKTurnBasedMatch

I want to let the user to either create new match or join existing matches which are created using create new match, all to be done programmatically. My question is how can I force game center to only create a new match ? The code which apple provided in their document is:
-(IBAction)findProgrammaticMatch:(id)sender {
GKMatchRequest *request = [[GKMatchRequest alloc] init];
request.minPlayers = 2;
request.maxPlayers = 2;
[GKTurnBasedMatch findMatchForRequest:request withCompletionHandler:^(GKTurnBasedMatch *match,NSError *error) {
if (match)
// load gameplay
}];
}
this code will create a new match if and only if there is no existing match, otherwise it will make auto-match.
Use playerAttributes property on the GKMatchRequest:
GKMatchRequest *request = [[GKMatchRequest alloc] init];
request.minPlayers = 2;
request.maxPlayers = 2;
if (wantsNewGame)
request.playerAttribute = 0x0000FFFF;
else if (wantsJoin)
request.playerAttribute = 0xFFFF0000;
else // don't care
request.playerAttribute = 0xFFFFFFFF;
GKTurnBasedMatchmakerViewController *vc = [[GKTurnBasedMatchmakerViewController alloc] initWithMatchRequest:request];

Core Data Problems with saving changes in NSManagedObjectContext

I am experiencing problems with how I handle my Core Data NSManagedObjectContext.
I can create NSManagedObject in my NSManagedObjectContext, but I failed to save the value.
Here's what I got:
_lesson.title = _titleField.text;
int priority = [_priorityField.text intValue];
int difficulty = [_difficultyField.text intValue];
int time = [_timeField.text intValue];
int sortIndex = 0;
if ( time == 0 )
{
sortIndex = 101;
}
else
{
sortIndex = priority * ( difficulty / time );
}
_lesson.priority = [NSNumber numberWithInt:priority];
_lesson.difficulty = [NSNumber numberWithInt:difficulty];
_lesson.time = [NSNumber numberWithInt:time];
_lesson.sortIndex = [NSNumber numberWithInt:sortIndex];
NSError* error = nil;
[[(AppDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext] save:&error];
Everything before the saving is working perfectly, I used NSLog to verify if each value is really saved in _lesson.
And _lesson is sent from here:
if ( [[segue identifier] isEqualToString:#"addLesson"] )
{
LessonViewController* destination = [[LessonViewController alloc]init];
Lesson* lesson = (Lesson*)[NSEntityDescription insertNewObjectForEntityForName:#"Lesson" inManagedObjectContext:_managedObjectContext];
destination.lesson = lesson;
}
else if ( [[segue identifier] isEqualToString:#"editLesson"] )
{
LessonViewController* destination = [[LessonViewController alloc]init];
NSIndexPath* index = [_tableView indexPathForCell:(UITableViewCell*)sender];
[_managedObjectContext deleteObject:[_lessonArray objectAtIndex:index.row]];
Lesson* lesson = (Lesson*)[_lessonArray objectAtIndex:index.row];
destination.lesson = lesson;
}
After debugging for two hours, I cannot find my error. Please help!
I will include my full code below:
https://www.dropbox.com/sh/eu62ie9svbbqdmm/u1hYUICfjy
That is my full source code. (I copied and pasted and created a mess. So, Dropbox!)
Thanks in advance.
This line looks suspicious:
[_managedObjectContext deleteObject:[_lessonArray objectAtIndex:index.row]];
You delete the Lesson object before passing it to the LessonViewController, so that saving the context will delete that object from the store, and not save a (modified) object, as you probably intended.
It seems to me that you should just delete that line in your code.
ADDED: There is an error in your prepareForSegue method: You create a new view controller with
LessonViewController* destination = [[LessonViewController alloc]init];
Instead, you must use the destination view controller of the seque:
LessonViewController *destination = [segue destinationViewController];

Store array of ABRecordRef

How can we store and access a list of ABRecordRef so that we can use this in another class and later on?
You can get recordId from the record of type ABRecordRef from
addressBook Then convert it into NSString. Store it in NSUserDefaults
When you want to fetch the record...
fetch that recordId from NSUserDefaults,Convert it in integer
then use
ABRecordRef myRecord =
ABAddressBookGetPersonWithRecordID(addressBook, recordId);
So you will get the record which you saved earlier.
Try This:
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef person = ABRecordGetRecordID(1); // Or whatever you're using to get the record.
// do this for each piece of information you need:
NSString *firstName = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSString *lastName = (NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
// Get your receiving dict ready:
NSMutableDictionary *personDict = [NSMutableDictionary dictionary];
// then test them for a value (don't want nil values in the dictionary)
// Add each value as you test it.
if (firstName) {
[personDict setObject:firstName forKey:#"FistName"];
}
if (lastName) {
[personDict setObject:lastName forKey:#"LastName"];
}
// Add the personDict to NSUserDefaults:
[[NSUserDefaults standardDefaults] setObject:personDict forKey:#"MyPersonsDictionary"];
// Clean up after yourself:
[firstName release];
[lastNmae release];
That should be it.

How do NSEntityDescription and NSAttributeDescription work?

I am trying to understand how these things work : NSEntityDescription, NSAttributeDescription, attributeType.
I think these few lines of code work, since I get what I expect for the value of X.
Can some one tell me how I should modify the inner part of the loop, that is the line : X++;
in order to get the names and type of the properties in the entity : "myentity" ?
//::::::::::::::::::::::::::: EXPERIMENT
MeDaSyAGAppDelegate *TheAppDelegate=[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *TheContext=[TheAppDelegate managedObjectContext];
NSEntityDescription *TheEntityDesc;
TheEntityDesc=[NSEntityDescription entityForName:#"myentity" inManagedObjectContext:TheContext];
int X=0;
NSDictionary *attribs=[TheEntityDesc attributesByName];
for (NSAttributeDescription *eachA in [attribs allValues]) {
X++;
}
[self showMessageBox:[NSString stringWithFormat:#"X = %d.",X]];
//::::::::::::::::::::::::::: EXPERIMENT
First: Format your code. See below.
Second: try to do this:
NSLog(#"%#",eachA.name);//The name
NSLog(#"%d",[eachA attributeType])//The type, this is an integer
NSLog(#"%#",[eachA attributeValueClassName]);//Class name receiver
See:NSAttributeDescription Class Docs
Formatting: This looks better. (Attributes start with lower cases and use spaces)
//::::::::::::::::::::::::::: EXPERIMENT
MeDaSyAGAppDelegate *theAppDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *theContext = [TheAppDelegate managedObjectContext];
NSEntityDescription *theEntityDesc = [NSEntityDescription entityForName:#"myentity" inManagedObjectContext:TheContext];
int X = 0;
NSDictionary *attribs = [theEntityDesc attributesByName];
for (NSAttributeDescription *eachA in [attribs allValues]) {
X++;
}
[self showMessageBox:[NSString stringWithFormat:#"X = %d.", X]];
//::::::::::::::::::::::::::: EXPERIMENT

Resources