To learn about Core Data, I'm making a quiz app but it doesn't use a table view. I have the data for two quizzes seeded in the application. When a user clicks on a button on the view, I want to fetch a quiz, depending on which button he/she presses, but I'm not sure what I can put in for the predicate
if ([sender.currentTitle isEqualToString:#"sports"]){
NSError *error;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Quizdata"
inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat: #"(SELF = %#)", ????]; ///unsure what to put here
[fetchRequest setPredicate:predicate];
self.fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
NSLog(#"fetched object %#", fetchedObjects);
}else if ([sender.currentTitle isEqualToString:#"entertainment"]){
NSLog(#"entertainment%#", sender.currentTitle);
}
I have two entities, for example Quiz.h, which I made classes for based on the attributes of the entities
#dynamic quizId;
#dynamic name;
#dynamic quizData;
and a QuizData.h entity
#dynamic answer1;
#dynamic answer2;
#dynamic answer3;
#dynamic answer4;
#dynamic correctAnswer;
#dynamic question;
#dynamic score;
#dynamic unique;
#dynamic quiz;
I had hoped to be able to fetch one of the two quizzes by doing something similar to what I'd do in Rails
Quizdata.where(quizId => 1)
Is it possible to only fetch the sports questions the way that I've done it (i.e. without using a table view). The reason why I thought tableView might be important is that it'll have object ids. I can't figure out how to get CoreData to retrieve every question for quizId 1.
I had previously imported data like this with json
{ "question" : "Do you like basketball", "answer1": "yes", "answer2": "no", "answer3": "maybe", "answer4":"of course", "correctAnswer": "yes", "unique": "2", "name": "sportsquiz", "quizId": "1"},
and then inserted and saved it with the two classes
Sure ...
I don't completely follow the logic on your Model As i'm not seeing a relationship between Quiz and QuizData.
If you had one, you would have an NSSet in Quiz containing a collection of QuizData. The you would simply perform an NSFetchRequest like this;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Quiz" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"quizId >= %#", [NSNumber numberWithInt:1]];
[fetchRequest setPredicate:predicate];
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
FetchedObjects would contain an array of "Quiz" objects whose quizId >= 1. If you had set up your relationships correctly, each quiz object would contain a collection of quizData objects.
The main thing to remember is that Core Data is an Object Graph. As such, you would add quizData Objects to your Quiz object (as opposed to setting a relationship field and adding the relationship key to the Quiz object).
Related
I have "WorkoutList" object in CoreData, which contains field
#property (nullable, nonatomic, retain) NSSet<Workout *> *workoutList;
and have relationship one to many ("Workout" objects). Workout objects contain field named "finish", this is a string. I am trying to get an array of objects in which field "finish" and my string are equal.
NSEntityDescription* entity = [NSEntityDescription entityForName:#"WorkoutList" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity: entity];
if (dateString)
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"workoutList.finish == %#", dateString];
[fetchRequest setPredicate:predicate];
}
NSArray* fetchWorkoutList = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
But I can't write correct predicate for that. So my question is what is correct predicate in this example? Thanks in advance.
The correct predicate was #"ANY workoutList.finish == %#".
in my app i have two entities: Members and Lists. they both have a one-to-many relationships (member can have more than one list, list can have more than one member). now i want to fetch the lists belonging to a specific member. here is my code:
WSAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Lists" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"has_members contains[cd] %#", [self.currentMember valueForKey:#"name"]]];
[fetchRequest setPredicate:predicate];
NSError *error;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
// Handle the error.
NSLog(#"NO LISTS AVAILABLE IN REFRESH");
}
self.currentMember is a managed object of the user himself.
Note: member has name, (NSSet*) member_of_list
list has list_name, has-members
Problem: when i run the code it's breaking at the fetchedObjects array. i suspect that there is something wrong with the NSPredicate but i don't know where and how to fix it. can any one point out the problem?
First, the relationship you describe between Member (Calling an entity in a plural form is confusing) and List is many-to-many.
Second, instead of using CoreData's inherent object graph capabilities, you went and "rolled your own" relationship between the entities (you should use your interface builder to model a CoreData relationship between the two entities).
See HERE how to do that.
after you model your data, your predicate should look something like:
//Not tested
NSPredicate* p = [NSPredicate predicateWithFormat:#"ANY members = %#",self.currentMember];
DO NOT pass a formatted string to create the predicate, use NSPredicate formatting to substitute parameters or you will not be able to accomplish your goal (in most cases).
How can I add a Subcategorie to a Categorie?
And how can I get the specific Subcategorie's of a Categorie?
I need something like
get Subcategorie.denumire where Categorie.denumire == "somename"
and
add mySubcategorie to Categorie.denumire where Categorie.denumire == "somename"
How can I do this? How can I get the name of a subtable's parent table and the names of the subtables of a table?
When you generate NSManagedObject Entities, Goal class will have an NSSet called toMinorGoal (assuming, your toMinorGoal is unordered relationship). Also, XCode will generate 4 accessory methods to add/remove MinorGoal objects to/from relationship.
If you need to fetch MinorGoals object, you would just need to get Goal object and then access its toMinorGoals NSSet that will contain all of its MinorGoal objects. Alternatively, you can just fetch MinorGoal objects, but these will return every single one of them (if you don't specify how many you want).
This is an approximate example of generated accessors XCode will provide you with:
- (void)addtoMinorGoaObject:(MinorGoal *)value;
- (void)removetoMinorGoalObject:(MinorGoal *)value;
- (void)addtoMinorGoal:(NSSet *)value;
- (void)removetoMinorGoal:(NSSet *)value;
Hope it helped you.
After a few day's of trying different solutions I finally figured this out thanks to this tutorial on CoreData :
http://www.raywenderlich.com/934/core-data-tutorial-for-ios-getting-started
I fetched all the subtables Subcategorie of the table Categorie like this:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Subcategorie"
inManagedObjectContext:self.managedObjectContext];
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"categorii.denumire == %#",self.title];
[fetchRequest setPredicate:predicate];
[fetchRequest setEntity:entity];
NSError *error;
self.listaElementeBD = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
self.title is the denumire of the Categorie, hope this helps.
I'm just getting started with Core Data and am not sure how this works. I basically have a Person entity and an alarm entity. Each person can have many alarms. What I want is to go to a detailViewController of the person object and see their alarms. Because NSSet isn't sorted, I have a method to return the alarms sorted like so:
- (NSArray *)sortedTimes {
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Alarm" inManagedObjectContext:self.managedObjectContext];
[request setEntity:entity];
NSSortDescriptor *timeDescriptor = [[NSSortDescriptor alloc] initWithKey:#"time" ascending:YES selector:#selector(compare:)];
[request setSortDescriptors:#[timeDescriptor]];
NSError *error = nil;
NSArray *objects = [self.managedObjectContext executeFetchRequest:request error:&error];
// Can I do this???
//self.person.alarms = [NSSet setWithArray:objects];
// for (NSManagedObject *obj in objects) {
// NSDate *date = [obj valueForKey:#"time"];
// NSLog(#"date: %#", [date description]);
// }
return objects;
}
What I'm wondering is, in the line self.person.alarms = [NSSet setWithArray:objects]; is that ok? I guess I'm not sure as to what actually is happening. My executeFetchRequest returns an array of the objects I want. Can I just go ahead and assign it to the person entity's alarm property? I wasn't sure if there was a relationship from Person->Alarm that I should not be mucking with, or if something like this is perfectly legal. Thanks!
First of all, your fetch request returns all alarms, not only the alarms of self.person. You have to add an predicate to the fetch request:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"person = %#", self.person];
[request setPredicate:predicate];
(assuming that person is the inverse relationship from the Alarm entity to the Person entity). But you don't really need a fetch request to get the sorted alarms of a person. A more direct way is
NSArray *objects = [[self.person.alarms allObjects]
sortedArrayUsingDescriptors:#[timeDescriptor]];
Now to your question: The statement
self.person.alarms = [NSSet setWithArray:objects];
just re-assigns the same set of alarms to the person. This effectively does not change anything, because it is the same set. In particular, it does not guarantee that self.person.alarms will now be sorted by time.
Remark: It you want to display a table view with the alarms of a person, you can also use a NSFetchedResultsController (FRC) as table view data source. The advantage of using a FRC is that the table view is automatically updated if objects are inserted, removed or updated.
Have a look at the NSFetchedResultsController and NSFetchedResultsControllerDelegate documentation which contains all the required code templates.
my program has a sqlite database with two related tables. One called "Rank" and other one called "Requirement"
I want to fetch all rows from the "Requirement" table that has a relationship with the specific row in a "Rank" table. Following is my code, it grabs the whole table, but I get the specified rows only according to the above mentioned rule.
-(NSArray *) getAllRequirementsForTheRank:(Rank *) rank
{
NSError *error;
NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init]autorelease];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Requirement" inManagedObjectContext:self.context];
[fetchRequest setEntity:entity];
NSPredicate *searchType = [NSPredicate predicateWithFormat:#"Rank = %#", rank];
[fetchRequest setPredicate:searchType];
NSArray *scoutRequirementArray = [self.context executeFetchRequest:fetchRequest error:&error];
for (Requirement *r in scoutRequirementArray)
{
NSLog(#"Requirementttt : %# :", r.requirementName);
}
return scoutRequirementArray;
}
If you have the relationship modelled in core data, just get the linked objects from the relationship property. You don't need another fetch request. rank.requirements will give you an NSSet of everything you need. (I'm assuming names for your object and properties here).