Core Data Fault - objective-c

I am mapping Json Data from Server using Restkit and I am Displaying those data by fetching from db.
There is a refresh button in my view which performs the above operation again.
Scenario:
I have two tables Key & Profile which has one-one relationship. I am fetching data from DB using follwing code
NSFetchRequest *fetchRequest = [Key fetchRequest];
[fetchRequest setRelationshipKeyPathsForPrefetching:[NSArray arrayWithObject:#"Profile"]];
[fetchRequest setIncludesSubentities:YES];
NSArray *sortedObjects = [Key executeFetchRequest:fetchRequest];
Above array returns all object in DB. but when i check that using breakpoint, i got some core data fault which was the reason for not showing all the data.
//All data in sortedObjects are like this.
<Key: 0x889f2f0> (entity: Key; id: 0x889e400 <x-coredata://981A476D-55AC-4CB4-BBD8-E0285E522412/Key/p1489> ; data: <fault>)
Any idea

This might be a misunderstanding about what a 'fault' is.
As described in Apple's documentation:
Faulting is a mechanism Core Data employs to reduce your application’s memory usage.
and
A fault is a placeholder object that represents a managed object that has not yet been fully realized, or a collection object that represents a relationship:
So, if you see the word 'fault' in logs when you're working with Core Data, it doesn't mean that an error has occurred. What unexpected behaviour are you seeing in your app?

You haven't actually described a problem. A Core Data fault isn't an error-- it's more like a page fault in a file system. It just means that the data hasn't been read yet. What you're describing is completely normal and expected. If you access any of the attributes of the returned objects, the fault will be automatically filled and you'll see the results. So if your Key entity has an attribute called name, you can still look up the value(s) for name and even log them if you want.
You could force the faults to be filled by adding this before executing the fetch request:
[fetchRequest setReturnsObjectsAsFaults:NO];
It's not necessary though and, depending on what attributes you have and how many objects you fetch, could use a lot more memory than is really needed.

Related

CoreData - trouble accessing relationships

My data model looks like this:
Object A <----->> Object B <-----> Object C
I fetch a group of Object A's from Core Data via an NSFetchedResultsController. For one particular object in this group, I know that it has only one Object B related to it and I want to retrieve the Object C.
I'm trying to do that like this:
NSArray *bArray = [objectA.relationA allObjects];
ObjectB *myB = bArray[0];
ObjectC *myC = myB.relationB;
(I've also tried [myB valueForKey:#"relationB"] with the same result)
The problem is that I can't get the fault to fire for Object C - I keep getting this for myC:
$6 = 0x0a947c00 (entity: ObjectC; id: 0xa9680b0 ; data: )
I'm passing this value on to another view controller and it's still a fault when it's accessed there, which isn't terribly useful.
It seems silly to have to refetch when I have the object, but I don't know what else to do. All the threads I can find on this say that faults are normal and that they will be fired when you access the faulted object, but that doesn't seem to be happening here.
Any suggestions?
Update: I tried adding this:
[fetchRequest setRelationshipKeyPathsForPrefetching:#[#"relationA.relationB"]];
But it did not make any difference.
The problem is that I can't get the fault to fire for Object C - I
keep getting this for myC:
$6 = 0x0a947c00 (entity: ObjectC; id: 0xa9680b0 ; data: )
You haven't tried to access myC yet. myC will remain a fault until you use it somehow. From the docs:
Fault handling is transparent—you do not have to execute a fetch to
realize a fault. If at some stage a persistent property of a fault
object is accessed, then Core Data automatically retrieves the data
for the object and initializes the object (see NSManagedObject Class
Reference for a list of methods that do not cause faults to fire).
This process is commonly referred to as firing the fault.
So, (assuming ObjectC has a name property) if you do something like:
NSString *name = myC.name;
you should find that the fault at myC fires and you'll automagically have a real object to work with.
All the threads I can find on this say that faults are normal and that
they will be fired when you access the faulted object, but that
doesn't seem to be happening here.
They're right. Unless there's more that you haven't told us, it sounds like you're just expecting the fault to fire at a different time, i.e. when you assign the object to myC. But again, the fault won't fire until you do something to the fault, like getting or setting a property.

How can i save JSON objects to Core Data?

I'm a nwebie in Core Data, i have designed a navigation based application and some of the data i use are created on run time(come from a URL via JSON). I took a few tutorials an searched for almost a day but haven't still realized how to save the incoming JSON data to the Entity (or event?) in my Core Data model. I fetch the data in the DetailViewController class and i need to save this data to Core Data(I have prepared an Entity with 7 properties). Can anyone please help?(If you know a good tutorial or sample code i will be pleased)
EDIT This may be a little specific but i really have trouble with and need just a little help.
My data comes to the app from a kind of restful server(i wrote it in PHP), firstly user enters his/her login informations(which i have saved to the database on server before) and when the response data comes i will use different elements of it in differen views(for example the user_id will be used on a view and the buttonData etc on other views). My question is, how will i save JSON data into my core data model(has tree Entities for the moment). Thanks in advance
Note: I lokked arround a lot but couldn't find any answer&tutorial about an app like mine
The best way to do that would be to create entities corresponding to JSON structure. Easiest was is when each JSON object becomes an entity, and arrays become arrays of entities. Be reasonable, however, and don't introduce too much overkill for JSON subobjects that are essentially part of its superobject.
When you have created entities, you can start off with the parsing and translation. Use some JSON framework (starting from iOS5 there's one from Apple) and parse JSON string into object tree, where root item is either an NSArray or NSDictionary, and subelements will be NSArray, NSDictionary, NSNumber, NSString or NSNull.
Go over them one by one in iterational loops and assign according values to your core data entity attributes. You can make use of NSKeyValueCoding here and avoid too much manual mapping of the attribute names. If your JSON attributes are of the same name as entity attributes, you'll be able to just go over all dictionary elements and parse them into attributes of the same name.
Example
My parsing code in the similar situation was as follows:
NSDictionary *parsedFeed = /* your way to get a dictionary */;
for (NSString *key in parsedFeed) {
id value = [parsedFeed objectForKey:key];
// Don't assign NSNull, it will break assignments to NSString, etc.
if (value && [value isKindOfClass:[NSNull class]])
value = nil;
#try {
[yourCreatedEntity setValue:value forKey:property];
} #catch (NSException *exception) {
// Exception means such attribute is not defined in the class or some other error.
}
}
This code will work in trivial situation, however, it may need to be expanded, depending on your needs:
With some kinds of custom mappings in case you want your JSON value be placed in differently named attribute.
If your JSON has sub-objects or arrays of sub-objects, you will need to detect those cases, for example in setters, and initiate new parsing one level deeper. Otherwise with my example you will face the situation that assigns NSDictionary object to an NSManagedObject.
I don't think it is reasonable to dive into these, more advanced matters in scope of this answer, as it will expand it too much.
I suggest you to use this library : https://github.com/TouchCode/TouchJSON
And then if you want to make a factory to parse json and feed your code data, you can use selectors to call methods to fill all your attributes.
Chances are your JSON data gets converted to an NSDictionary or NSArray (or some combination of the two). Simply extract the key/values from the JSON structure and add them to your entity class.
This lib helps me lot
Features
Attribute and relationship mapping to JSON key paths.
Value transformation using named NSValueTransformer objects.
Object graph preservation.
Support for entity inheritance
Works vice-versa

NSFetchRequest not catching objects that have a changed property

I have run into a weird problem with CoreData on MacOsX 10.6 using an SQL store. I have an NSManagedObject subclass called Family with attribute name and a relationship personList connected to another NSManagedObject subclass called Person with attribute firstname and inverse relationship family. A Person has only one family, and a family can have several Persons.
Say I have a Family object family pointing to the family 'Doe' with 2 Person (John and Jane) connected to it and I do the following request:
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:[NSEntityDescription entityForName:#"Person" inManagedObjectContext:managedObjectContext]];
[request setPredicate:[NSPredicate predicateWithFormat:#"family.name=%#",[family name]]];
NSArray *array = [managedObjectContext executeFetchRequest:request error:&error];
I get an array of size 2 with the 2 persons: Jane and John, with Family name Doe. Now, if I update the Family using its synthesized accessor, in my case:
[family setName:#"Wheat"]
I cannot after get the list of Person using the same fetch request. The results is an [array count] of 0.
If I change the predicate to the following line, it works again:
[request setPredicate:[NSPredicate predicateWithFormat:#"family=%#",family]];
So it is as if the Predicate is not using the updated version of the property name of the family, even though I have the NSFetchRequest set to the defaults (so includesPendingChanges returns YES). That makes no sense to me. It seems that the NSFetchRequest finds the family object, but fails to see that its value family.name has been updated, not saved, and is in the managedObjectContext in memory. Of course, if I save the store, then it works again.
Any idea? I have been through the Mac documentation and cannot see why this would fail.
I think the key here is understanding the fetch request. It retrieves data from the persistent store, so clearly, if you did not save to the persistent store, it will not find that data. The situation you describe is entirely logical if you take that into account.
From the Core Data Programming Guide:
You cannot fetch using a predicate based on transient properties
(although you can use transient properties to filter in memory
yourself). Moreover, there are some interactions between fetching and
the type of store—for details, see “Store Types and Behaviors.” To
summarize, though, if you execute a fetch directly, you should
typically not add Objective-C-based predicates or sort descriptors to
the fetch request. Instead you should apply these to the results of
the fetch. If you use an array controller, you may need to subclass
NSArrayController so you can have it not pass the sort descriptors to
the persistent store and instead do the sorting after your data has
been fetched.
To summarize, I have been testing thoroughly my code and here is how I perceive the limitations of CoreData regarding Fetching and objective-c predicated (ie the dot notation).
If an object has been access by the Objective-C program and if one of its property or relationship has been modified, any NSFetchRequest with a predicate using a dot notation will return the structure of the SQL store, hence the results will be erroneous.
In the case of the trivial Family and Person example, if you have a link to a Family and change its name, any query made on the Person NSEntity cannot include a predicate with the following query item
#"family.name=%#"
It will indeed query using the family name in the SQL store. However, the following query will work after such a change:
#"family=%#"
Indeed, the NSFetchRequest will still retrieve the info in the store, but since the structure has not changed, it will replace the objects retrieved by those in Memory, so a subsequent test to [family name] will return the updated name.
With care, you can use nested Predicate such as:
#"person.family.name=%#"
As long as you can guarantee that all the objects that have the property person, have not their family altered, nor their name altered. If it's not the case, then you can at best call
#"person.family=%#"
Or if you can't guarantee that all the Family objects are untouched, only
#"person=%#"
Of course, an alternative is to systematically SAVE: the NSManagedObjects to the persistent store every time you make any change, so all properties are updated and then all the above notations would work. There are times however when you do want to prevent savings and force the customer to change it's document only if he wishes (think about Word, Excel, Picture tools, etc..). Hope this is of help.
If by "using the same fetch request", you mean using the very same instance of the fetch request that you constructed the first time, then this is no surprise. The predicate you applied is "family.name = Doe". Once the family's name is "Wheat", the fetch request's predicate no longer matches it, because "Wheat" != "Doe".
To retrieve the family after changing its name, you would need to create a new instance of NSFetchRequest using a predicate matching the new family name.
If by "using the same fetch request", you mean using a different fetch request constructed using the same code, well, then I would think about #Mundi's answer.

NSFetchRequest and predicateWithBlock

I am playing with an app that uses Core Data and NSManagedObjects to populate a UITableView. There is only one class in my application, called Event. I have created the following custom instance method on Event:
- (BOOL)isExpired {
return ([[self.endOn dateAtEndOfDay] timeIntervalSinceNow] < 0);
}
I would like to limit the UITableView that displays Event objects to only the Events that are expired - that is, where isExpired returns YES. I have tried to do this by adding an NSPredicate to the NSFetchRequest:
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary * bindings) {return([evaluatedObject isExpired]);}];
[fetchRequest setPredicate:predicate];
but I get the error: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Problem with subpredicate BLOCKPREDICATE(0x272ac)'
***. Does this mean that you can't use a block predicate with an NSFetchRequest? Or have I just constructed it improperly?
Thank you!
So, it appears that we've established in the comments to the original post that this is likely caused by SQLite stores being incompatible with block predicates, since Core Data cannot translate these to SQL to run them in the store (thanks, JoostK).
There might be a couple of ways to overcome this:
Provided that the end date of your entities is a regular attribute, you might be able to express the expiry constraint as a predicate format string instead of a block predicate, which Core Data should be able to translate into a SQL clause.
If the above is possible, you will probably prefer to use a fetch request template to retrieve the expired items. You would need to pass in a substitution variable like $NOW to give access to the current date, though. This has the advantage of making the predicate template show up in the model editor.
Both approaches, however, have the disadvantage of duplicating existing functionality (i.e., your isExpired method). So another way would be fetch all qualifiying entities regardless of their expiry state first, and then run a dedicated filtering step on the resulting set of entities to weed out the non-expired ones. Since by that point, they have been fully resurrected from the store, you should be able to use a block predicate for this.
You can do a normal fetch request without specifying the predicate, and afterwards filter the resulting array:
NSArray *allEvents = [context executeFetchRequest:fetchRequest];
if (!allEvents) { // do error handling here
}
NSArray *expiredEvents = [allEvents filteredArrayUsingPredicate:predicate];

How to get the ID of an object saved to Core Data's managed object context?

I have this code:
NSEntityDescription *userEntity = [[[engine managedObjectModel] entitiesByName] objectForKey:#"User"];
User *user = [[User alloc] initWithEntity:userEntity insertIntoManagedObjectContext:[engine managedObjectContext]];
and I want to know the id of the object inserted to the managed object context. How can i get that?
Will that id remain the same for that object's lifetime or will it persist to the sqlLite database beneath this and be something that can be used to uniquely identify it during a fetch operation (my ultimate goal).
Any help appreciated // :)
If you want to save an object's ID permanently you need to:
Save the object into the context so that the ID changes from a temporary to a permanent ID.
Extract the URI version of the permanent ID with -[NSManagedObjectID URIRepresentation]. That returns a NSURL you can store as transformable attribute in another managed object.
You can get the object by using -[NSPersistentStoreCoordinator managedObjectIDForURIRepresentation:] to generate a new NSManagedObjectID object and then use -[NSManagedObjectContext objectWithID:] to get the actual referenced managed object.
The URI is supposed to identify a particular object in a particular store on a particular computer but it can change if you make any structural changes to the store such as migrating it to a new model version.
However, you probably don't need to do any of this. ObjectIDs play a much smaller role in Core Data than they do in other Data Model systems. Core Data maintains an object graph that uniquely identifies objects by their location in the graph. Simply walking the graph relationships takes you to a specific unique object.
The only time you really need ObjectID is when you're accessing object across two or more persistent stores. You need them then because relationships don't cross stores.
Read up on "managed object IDs" in the Core Data Programming Guide
You can get the object id from the object with something like:
NSManagedObjectID *moID = [managedObject objectID];
First, you are constructing your objects in a non-preferred manner. Generally you should:
User *user = [NSEntityDescription insertEntityForName:#"User" intoManagedObjectContext:[engine managedObjectContext]];
Second, when you create the object it will get a temporary id which you can access via [user objectID] as David mentioned. Once you save the context then it will get a new "permanent" id.
However this id can and does change over the lifetime of the entity (although not the instance). Things like migrating the data can cause this id to change. However, between saving the context and exiting the application the id will remain the same.