Access object of to-many relationship - objective-c

I have an object with a to-many relationship. It goes Workout<-->>Workout Score. If I have the workout score, how can I access the workout? I am using Parse.com.
Assuming workoutScore is a PFObject, and has been retrieved, I have a relationship called whichWorkout on it. The object returned is the workout, however I cannot access it's properties. Am I doing something wrong?
// Assuming this score has been retrieved by a PFQuery
PFObject *workoutScore;
PFObject *actualWorkout = workoutScore[#"whichWorkout"];
// Now when I try to access a property of actualWorkout, I can't
NSString *name = actualWorkout[#"name"];
If I just query for the actual workout, the same code works. Is there any way to access properties of objects retrieved via pointer relationships using Parse?

If you are running a query on the workoutScore you should use [query include:#"workout"]. This will pull the object that is being pointed to (the actualWorkout) and get everything you need in one call
PFQuery query = [PFQuery queryWithClassName:#"WorkoutScore"];
[query includeKey:#"workout"];
[query findAllInBackground....
The other option is to call fetch on the actual workout. This will be a second call after you have fetched the workoutScore. If you know you are going to need the workout probably better to get it during the query with the include.
PFObject *actualWorkout = workoutScore[#"whichWorkout"];
// There are asynchronous versions of fetch too
// which would be recommended
[actualWorkout fetch];
// actualWorkout will now have its data.
NSString *name = actualWorkout[#"name"];

If WorkoutScore has a back pointer to Workout (it looks like it does from your code, called whichWorkout), then it's easy. When querying WorkoutScore, use includeKey: to aggressively fetch the related object:
[workoutScoreQuery includeKey:#"whichWorkout"];

If the many to many relationship is a PFRelation, you'll have to query it as a second step
PFRelation *relation = [parseObject relationForKey:#"relationName"];
PFQuery *query = [[relation query] findObjectsInBackground:...];
If the many to many relationship is just an array of pointers, you need to tell the query to include the actual data:
[workoutScoreQuery includeKey:#"whichWorkout"];

Related

MagicalRecord get all entities from one to many relationship where relationship id is x

Say I have an entity called Message, and an entity called Group. Every group can have many messages (one to many relationship).
How do I use MagicalRecord to get all the messages of a group, WITHOUT first loading the group?
NSArray *entities = [Message MR_findAllSortedBy:#"groupID:x" ascending:NO];
I thought of just adding an attribute groupID to message, but it seems very wrong... (since obviously the relationship is saved in my db in some other way)
Probably something like:
NSArray *messagesInGroup = [Message MR_findAllSortedBy:#"group.groupID" ascending:NO]
The sortedBy parameter just translates into the [NSSortDescriptor sortDescriptorWithKey:ascending:] method. According to the documentation, that first parameter is a keyPath, so as long as it's valid (ie. exists), it will work for you.

Can I construct a PFQuery that queries all classes?

i have an ios application in which i create a number of different classes of PFObjects, and i use pinning to the local datastore to take care of situations when i don't have network connectivity.
i'd like to query the local datastore from time to time in order to get all the objects in the store, irrespective of class.
i haven't been able to do this yet. the following code works fine and finds all the items of class MyClass
PFQuery *localStoreQuery = [[PFQuery alloc] initWithClassName:#"MyClass"];
[localStoreQuery fromLocalDatastore];
NSArray *results = [localStoreQuery findObjects];
but the following gives the error [Error]: bad characters in classname: (null) (Code: 103, Version: 1.8.5)
PFQuery *localStoreQuery = [[PFQuery alloc] init];
[localStoreQuery fromLocalDatastore];
NSArray *results = [localStoreQuery findObjects];
i also tried putting in #"*" as the classname like so
PFQuery *localStoreQuery = [[PFQuery alloc] initWithClassName:#"MyClass"];
but this also fails
so...is there any way to generically grab all pinned items of all classes, or do i have to have a loop and query each class i am creating separately (ugh)?
any help much appreciated.
Unfortunately you cannot. Parse does not support multi-class queries. You'd have to do each one, or make a super class that contains pointers to the object you'd like.

Retrieve Specific Object from Core Data

I'm new to Core Data and wondering if it is possible to get an object based on it's attributes, more specifically, an uniqueID I assigned to it. I'm trying to do this because I'm interfacing with a web server, which provides data that will updated the Core Data. I want to search through each of the web server objects, check the timestamp, and if it's different, retrieve that object from core data, and update. I've looked at using existingObjectWithId but it seems like I would have to know which object I'm searching for, or the ID of that object. I've also thought about sorting the data in both arrays, and then checking each simultaneously, but didn't think that is viable.
Here is what I'm doing so far:
-(NSMutableArray*) updateRootBeers:(NSMutableArray*)webRootBeerList{
NSManagedObjectContext* moc = [self managedObjectContext];
NSFetchRequest* fetchRequest = [[NSFetchRequest alloc]initWithEntityName:#"Rootbeer"];
coreDataRootBeerList = [[moc executeFetchRequest:fetchRequest error:nil]mutableCopy];
//check to see if core data has data, if not, call function to populate the list
if (coreDataRootBeerList.count <=0) {
[self addRootBeerToCoreData:webRootBeerList];
}else{
//otherwise I want to update the core data object if object data is different.
for(RootBeer* currentRootBeer in webRootBeerList){
RootBeer* mRootBeer = [moc existingObjectWithId:currentRootBeer error:nil];
}
}
}
I've also thought about using nested for loops to check for the data in each array, but that seems like poor coding.
Any help or thoughts would be great.
You want to make an NSFetchRequest. You can set the entity and provide a Predicate. Really simple and clean.

Core data: executeFetchRequest vs performFetch

I want a thorough list regarding comparison between the two. Things I have known:
executeFetchRequest:
Message sent to MOC
Return an array of managed objects
Goal: fetch objects from persistent store to MOC
With table view: has nothing to do with table view
Frequency: often used in a loop, so could be called many many times
performFetch:
Message sent to FRC
After calling it, use fetchedObjects to return an array of managed objects
With table view: FRC is specifically for keeping managed objects and table view rows in sync, and use performFetch to initialize that process.
Frequency: often only once. Unless fetch request of FRC changes, no need to call performFetch a second time
Please correct me if I am wrong and append the list. Thank you.
About executeFetchRequest:
Message sent to MOC
Yes
Return an array of managed objects
Yes, but you can also change the type of results you want to retrieve. In NSFetchRequest you can set a different result type with:
- (void)setResultType:(NSFetchRequestResultType)type
where NSFetchRequestResultType can be of different types. Taken from Apple doc:
enum {
NSManagedObjectResultType = 0x00,
NSManagedObjectIDResultType = 0x01,
NSDictionaryResultType = 0x02
NSCountResultType = 0x04
};
typedef NSUInteger NSFetchRequestResultType;
Goal: fetch objects from persistent store to MOC
Yes, creating a NSFetchRequest and performing a request, it the same as creating a SELECT statement in SQL. If you also use a NSPredicate it's the same as using SELECT-WHERE statement.
With table view: has nothing to do with table view
Yes, but with retrieved data you can populate a table
Frequency: often used in a loop, so could be called many many times
It depends, on what you want to achieve. It could be within a loop or not. Executing the request within a loop could have impact on performance but I would not be worried on that. Under the hood Core Data maintains a sort of cache mechanism. Every time you perform a request, if data are not in the cache, Core Data executes a round trip on your store (e.g. sql file) and populate the cache with the objects it has retrieved. If you perform the same query, the round trip will not performed again due to the cache mechanism. Anyway, you could avoid to execute a request within the run loop, simply moving that request outside the loop.
About performFetch:
Message sent to FRC
Yes
After calling it, use fetchedObjects to return an array of managed
objects
Yes, but you can also retrieve an object with [_fetchedResultsController objectAtIndexPath:indexPath]; if you are populating a specific cell within a table.
Here I really suggest to read a nice tutorial on NSFetchedResultsController
With table view: FRC is specifically for keeping managed objects and
table view rows in sync, and use performFetch to initialize that
process.
Yes, a NSFetchedResultsController works in combination with a NSManagedObjectContext for you. Furthermore, it enables lazy loading of data. Suppose you have 1000 elements you retrieve and you want to display them in a UITableView. Setting a request for a NSFetchRequest like:
[fetchRequest setFetchBatchSize:20];
and using it with an instance of a NSFetchedResultsController, it allows to load 20 elements at first. Then when you scroll, other 20 elements are loaded, and so on. Without a NSFetchedResultsController you must implement this behavior manually. Refer to the tutorial I provided for further info.
Frequency: often only once. Unless fetch request of FRC changes, no
need to call performFetch a second time
It depends on what you want to achieve. Most of the time you could call it once.
Hope that helps.
Edit
You have to call performFetch explicitly. I like to create a property for NSFetchedResultsController in my header file (.h) like
#property (nonatomic, strong, readonly) NSFetchedResultsController* fetchedResultsController;
and synthesize it in your implementation file (.m) like
#synthesize fetchedResultsController = _fetchedResultsController;
Then always within the .m file override the getter to create an new instance of it:
- (NSFetchedResultsController*)fetchedResultsController
{
// it already exists, so return it
if(_fetchedResultsController) return _fetchedResultsController;
// else create it and return
_fetchedResultsController = // alloc-init here with complete setup
return _fetchedResultsController;
}
Once done, within your class (for example in viewDidLoad method) use it like
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
// Handle the error appropriately.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
You are comparing the wrong elements. NSFetchedResultsController uses the NSManagedObjectContext to perform the fetch, and under proper configuration, monitors the changes in the managed object context to verify the status of the fetch properties it is monitoring, but the actual fetches are done by the context. On both cases, NSManagedObjectContext does the fetch. The difference being that, using the NSManagedObjectContext directly, you get an NSArray type of object (the actual runtime class is different than an array you get using [NSArray array]), while NSFetchedResultsController has a different purpose (have a collection of results and monitor changes to the records and entity on its fetch request). In other words, NSFetchedResultsController works using the context, but it works different than just a simple collection of objects.
One observation: you shouldn't be using executeFetchRequest inside a loop, especially calling it "many many times". Each fetch has its performance cost. You can call executeFetchRequest once, and do a loop to check the result.

NSFetchedResultsController add Objects manually

I recently stumbled across a difficult problem..
I'm normally using a NSFetchedResultsController to get Data out of my CoreData, and display it within a TableViewController.
The problem I have now is that I can't get the results I want with a NSFetchRequest right away, because having a m:n relationship and I implemented a Table in Core Data (References) which stores the references to the Objects...
So what I do now is, I use a fetch Request:
NSArray* references = [self.context executeFetchRequest:fetchRequest error:&error];
and then iterate through this array to get my Objects:
for(References* ref in references)
{
Post* tmp = ref.ref_of_post;
}
So is there a way to manually add these objects to my NSFetchedResultsController or is there a possibility to get the wanted object trough a NSFetchRequest?
Thanks for your help.
Never mind that.
I just added these Objects to a NSMutableArray and then would use this Array in the same way as the NSFetchedResultsController..