I am using core data to save data from web services in my app. On the first time of running, app creates the core data instance and attributes and properties and save all the data. My question is that, when the application runs second time or many times, Is the core data creates its instance and properties and save all data again, or again and again? I am sorry if my question is not relevant.
Thanks
If the Webservice + code for storing data to coredata gets called every time you run app, core data will store objects again and again
You can solve this by 2 ways
If your data from server remains the same, you can set a flag and check that coredata insertion should execute only once
If you data from server may keep on changing, you can Update data instead of inserting it again to avoid duplicate records.
If u want to make sure the data is unique, u should make sure the data object should have a unique key.
For example:
#interface Person : NSManagedObject
#property (nonatomic, retain) NSNumber * pid;
#property (nonatomic, retain) NSString * name;
#end
The property of Person.pid should be unique. It means that u can only get one person max with the appointed pid.
So before u insert new object, u should query the db with NSFetchRequest(NSPredicate) like this:
NSNumber *aimPid;// the person's pid
NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"pid == %#", aimPid]];
If person exist, then just update and save.
If person not exist, then insert a new one and save.
More:https://developer.apple.com/library/mac/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSFetchRequest_Class/
Related
I'm trying to solve problem which appears during this case:
User can initiate data loading from external source, when data is loaded, it is saved via CoreData. Then it is displayed in some views and some other classes got references to NSManagedObjects.
Data loading can be initiated by other condition (for example, when application resumes from background). New external data is received, dataController deletes previous and creates new data. And here is the problem.
I want to notify all data consumers-classes that they should load new instances (send them references to deleted objects, so they can compare references with ones they own and determine should they ask for new data version or not). But after deletion consumer-class has reference to fault without properties, its ObjectID is useless (because new instance was saved) and I don't know how load its new version.
I can implement some NSManagedObject wrapper:
#interface Model : NSObject
- (id)initWithUniqueId:(id)uniqueId dataObject:(NSManagedObject *)dataObject;
#property (nonatomic, strong, readonly) id uniqueId;
#property (nonatomic, strong, readonly) NSManagedObject *dataObject;
#end
This object can reload itself after dataObject becomes fault. But maybe this approach is wrong and this overhead is not needed? And NSManagedObject should be deleted only if it is really deleted, not updated? And then if object is updated, we can use KVO to handle properties changes, and if object is deleted, we can observe NSManagedObjectContext notifications for changes and look for deleted objects.
I just want to know which way would you prefer and why (maybe you like some other approach)? Thanks in advance.
If you are using an external data source, your own version of some kind of unique ID makes sense.
Then everything becomes simple. You load the data, update the persistent store when you save the context, and send of a notification via the NSNotificationCenter. All listeners can now simply update their data by re-fetching.
(Fetched results controllers that implement the delegate methods do not even have to be notified via the notification center.)
Setup - using RestKit, along with it's abilities to store data in a CoreData store.
I'm trying to perform two separate GET operations:
issue/:issueId ==> this returns an Issue object, assuming one with that ID exists.
issue/:issueId/comment ==> this returns Comment objects, belonging to the issue matching issueId.
So, for the first call, that just gets an issue back. It will only return comments back if I pass in an extra parameter on the URL. Otherwise, it won't. Of course, if I do ask for it, then the objects get created just fine, and all the objects are connected correctly in my core-data store.
The objects that I'm mapping look like this:
#interface Issue : NSManagedObject
#property (nonatomic) int32_t issueId;
#property (nonatomic, retain) NSSet* comments;
// many other fields not shown.
#end
#interface Comment: NSManagedObject
#property (nonatomic) int32_t commentId;
// many other fields not shown.
#end
Issue has a collection of Comments. Comments don't know about their owning Issue.
So, all I'm trying to do is make it possible for both of these calls to exist.
For example, in our URLs, say "issueId" is 12345. So, if I make one call to http://example.com/issue/12345, I'd like the data to be written to my CoreData store. (This works great, btw). What I would like to happen next is to call "http://example.com/issue/12345/comments", and then have those comments write to the CoreData store, and also be connected to issue-12345, that's already there. That's the part that I'm having trouble with.
If anyone could offer guidance on this, I'd really appreciate it.
After reading this issue on the official repo, I would proceed like follows.
In you Core Data model add the inverse relationship Comment -> Issue, so that your Comment interface looks like
#interface Comment: NSManagedObject
#property (nonatomic, retain) Issue * issue;
#property (nonatomic) int32_t commentId;
// many other fields not shown.
#end
and make that relationship mandatory.
Now you have to setup your mapping adding that relationship, for instance
[issueMapping addRelationshipMappingWithSourceKeyPath:#"comments"
mapping:[self commentMapping]];
If my understanding is correct, RestKit should populate both relationships (the one-to-many Issue -> Comment and its inverse) for you.
I have an app that uses a read-only Core Data database (meaning I never write to the database). I have a view controller that fetches some core data entities and displays them in a table. So for example, I have a core data entity named Photo, and in my view controller I have, say #property (nonatomic, strong) NSArray *photos;, which is a list of Photo objects.
Now everything works fine when the app launches fresh. But when I go to that view and exit the app (so it's still in the background) and reenter it, the #property I've set up becomes nil. I still see all UITableViewCells currently on screen. When I attempt to scroll, though, the app crashes.
I have multiple views that use Core Data stuff, but some of them work just fine. I'm wondering why for some view controllers my Core Data object set up as a #property disappears when the app returns to foreground.
Thanks!
First recommendation: you should be using an NSFetchedResultsController rather than an array. This is much more efficient and will take care of all memory considerations for you, beside many other advantages. As a matter of fact, it was designed specifically to manage the datasource of a table view based on Core Data.
If you still want to use your array, I speculate that you failed to initialize it properly.
In your viewDidLoad method, do not just assign the fetched results from core data but do it with proper initialization:
self.photos = [[NSArray alloc] initWithArray:coreDataResults];
Now the array should persist.
I think I figured out what's wrong with my code. So this is what I did to fetch the core data stuff:
[DatabaseHelper openDatabase:#"database" usingBlock:^(UIManagedDocument *document) {
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"Shop"];
request.predicate = [NSPredicate predicateWithFormat:#"ecategory = %#", self.category];
NSError *error = nil;
NSArray *matches = [document.managedObjectContext executeFetchRequest:request error:&error];
self.shops = matches;
[self updateTable];
}];
This correctly fetches the results, but the problem is, although I think I retained the Core Data objects, they actually belong to a UIManagedDocumentContext, and I didn't retain that. So when the app returns to foreground, the context is gone, and the core data objects become nil.
So what I did is declare a new property: #property (nonatomic, strong) UIManagedDocument *database; and then set self.database = document; in the block. Now the controller will retain the context and everything works fine.
Given and coredata based app using an Indexcard metaphor. Each Indexcard can optionally have a one-to-many relationship with a number of other entities/tables; i.e. I'll use Momento's 'Moment' as a proxy for my Indexcard object and Momento's ancillaries of tags, locations, etc. , for these other objects/tables.
What is the 'fastest' way to show whether or not these foreign table relationships exist on probably the most important tableView in the entire app?
and
What would be the best approach for laying out the cell portion showing whether or not a relationship exists and the count of the number of each type of relationship?
Again, using Momento as a design pattern. With a link to a screenshot on Flickr (because stackOverflow won't let me post an image since I'm a noob.)
Maybe my ex-RDBMS stuff is contaminating my thinking, but they didn't do a mongo-join to get the values off to the right did they? [tags,events,people,locations]. There has to be a more elegant way that I'm just not seeing.
My thoughts for laying out the cells on the right was to possibly use some boolean if YES put up the icon and the count, but that seems pretty expensive for every cell.
I'm sure that the answer to this layout question would be driven by the approach taken in the first part of the problem. It doesn't seem that I would want to store ancillary relationships in the 'main/moment' IndexCard object for maintenance reasons.
Thanks in advance for any help.
If you set up a one-many relationship of indexcards to tags(or whatever), a fetched indexcard object should have an NSSet of tags as a property. Same for the others, and you should just be able to get the count of the set and display that next to each of the appropriate icons.
..Unless I'm misunderstanding your question.
edit: to answer the second part, you should indeed have a conditional in cellForRowAtIndex path that checks the count of each set and either just display it with the icon (possible to have 0 then, which is normally fine), or check whether it is 0 and hide the image if it is as you said. I don't think either solution will slow down your app since the data has already been fetched anyway by the time the cell is being rendered, but the solution where you just pass the count right through without checking if it's 0 would generally be fast overall.
edit to provide some sample code:
Your Core Data model would have an IndexCard entity and then an entity for each type of possible related object.
1)Model:
IndexCard - has a one-many relationship with each of the other entities
Tag
Location
Person
2)After creating this model and the corresponding Object classes you will end up with an IndexCard class that has the following in its header
#property (nonatomic, strong) NSSet *tags
#property (nonatomic, strong) NSSet *locations
#property (nonatomic, strong) NSSet *people
and of course the following in its implementation
#dynamic tags
#dynamic locations
#dynamic people
3)Now that we've established this Core Data model, we can perform an nsfetchrequest (of course when using a tableview, you should use an nsfetchedresultscontroller as it will dynamically fetch the IndexCards it needs as you're scrolling through the table). This code assumes that we have a usable NSManagedObjectContext in its scope (ideally passed in from the AppDelegate and set as an ivar) and that our IndexCard object has some sort of key/id property we can search by, lets call it "number"
NSNumber *numberWeWant = [NSNumber numberWithInt:1];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:#"IndexCard" inManagedObjectContext:ourContext];
request.predicate = [NSPredicate predicateWithFormat:#"number == %#", numberWeWant];
NSError *error = nil;
NSArray *results = [context executeFetchRequest:request error:&error];
//didn't bother error checking in case no IndexCard matches
IndexCard *ourCard = [results lastObject];
//you can now use these to display in the cell or hide the appropriate icons if they = 0
int numTags = ourCard.tags.count;
int numLocations = ourCard.locations.count;
int numPeople = ourCard.people.count;
//just a sample of how we would access the individual related objects
for(Tag *tag in ourCard.tags)
{
//do whatever you want with each tag here
}
Again, this code is just to fetch a single IndexCard. In an actual table you would be initializing an nsfetchedresultscontroller when loading the view that contains it, and then just accessing the IndexCard at the position matching IndexPath.row in cellForRowAtIndexPath.
This also assumes there are a finite number of types of objects that IndexCard can be related to. If the types can change and increase randomly, this approach would need to be modified.
Hopefully this helps.
I would like to separate my reference data from my user data in my Core Data model to simplify future updates of my app (and because, I plan to store the database on the cloud and there is no need to store reference data on the cloud as this is part of my application). Therefore, I've been looking for a while for a way to code a cross-store relationship using fetched properties. I have not found any example implementations of this.
I have a Core Data model using 2 configurations :
data model config 1 : UserData (entities relative to user)
data model config 2 : ReferenceData (entities relative to application itself)
I set up 2 different SQLite persistent stores for both config.
UserData config (and store) contains entity "User"
ReferenceData config (and store) contains entities "Type" and "Item".
I would like to create two single-way weak relationships as below :
A "User" has a unique "Type"
A "User" has many "Items"
Here are my questions :
How do I set up my properties?
Do I need 2 properties for each relation (one for storing Unique ID and another to access my fetched results)?
Could this weak relationship be ordered?
Could someone give me an example implementation of this?
As a follow-on to Marcus' answer:
Looking through the forums and docs, I read that I should use the URI Representation of my entity instance instead of objectID. What is the reason behind this?
// Get the URI of my object to reference
NSURL * uriObjectB [[myObjectB objectID] URIRepresentation];
Next, I wonder, how do I store my object B URI (NSURL) in my parent object A as a weak relationship? What attribute type should I use? How do I convert this? I heard about archive... ?
Then, later I should retrieve the managed object the same way (by unconvert/unarchive the URIRepresentation) and get Object from URI
// Get the Object ID from the URI
NSManagedObjectID* idObjectB = [storeCoordinator managedObjectIDForURIRepresentation:[[myManagedObject objectID] URIRepresentation]];
// Get the Managed Object for the idOjectB ...
And last but not least, shouId I declare two properties in my entity A, one for persisting of URI needs and another for retrieving direclty object B?
NSURL * uriObjectB [objectA uriObjectB];
ObjectB * myObjectB = [objectA objectB];
As you can read, I really miss some simple example to implement thes weak relationships ! I would really appreciate some help.
Splitting the data is the right answer by far. Reference data should not be synced with the cloud, especially since iCloud has soft caps on what it will allow an application to sync and store in documents.
To create soft references across to stores (they do not need to be SQLite but it is a good idea for general app performance) you will need to have some kind of unique key that can be referenced from the other side; a good old fashioned foreign key.
From there you can create a fetched property in the model to reference the entity.
While this relationship cannot be ordered directly you can create order via a sort index or if it has a logical sort then you can sort it once you retrieve the data (I use convenience methods for this that return a sorted array instead of a set).
I can build up an example but you really are on the right track. The only fun part is migration. When you detect a migration situation you will need to migrate each store independently before you build up your core data stack. It sounds tricky but it really is not that hard to accomplish.
Example
Imagine you have a UserBar entity in the user store and a RefBar entity in the reference store. The RefBar will then have a fetchedProperty "relationship" with a UserBar thereby creating a ToOne relationship.
UserBar
----------
refBarID : NSInteger
RefBar
--------
identifier : NSInteger
You can then create a fetched property on the RefBar entity in the modeler with a predicate of:
$FETCHED_PROPERTY.refBarID == identifier
Lets name that predicate "userBarFetched"
Now that will return an array so we want to add a convenience method to the RefBar
#class UserBar;
#interface RefBar : NSManagedObject
- (UserBar*)userBar;
#end
#implementation RefBar
- (UserBar*)userBar
{
NSArray *fetched = [self valueForKey:#"userBarFetched"];
return [fetched lastObject];
}
#end
To create a ToMany is the same except your convenience method would return an array and you would sort the array before returning it.
As Heath Borders mentioned, it is possible to add a sort to the NSFetchedProperty if you want but you must do it in code. Personally I have always found it wasteful and don't use that feature. It might be more useful if I could set the sort in the modeler.
Using the ObjectID
I do not recommend using the ObjectID or the URIRepresentation. The ObjectID (and therefore the URIRepresentation of that ObjectID) can and will change. Whenever you migrate a database that value will change. You are far better off creating a non-changing GUID.
The weak relationship
You only need a single value on the M side of the relationship and that stores the foreign identifier. In your object subclass you only need to implement accessors that retrieve the object (or objects).
I would go with just one store.
For storing stuff in the cloud, you will anyway have to serialize the data, either as JSON or SQL statements, or whatever scheme you prefer.
You will need a local copy of the data on the user's device, so he can access it quickly and offline. The cloud store can have only the user entity, while the local store (part of the app) can also have the reference entity.
I have a similar project with a huge reference store (20000 records) with geographic information, and user generated content ("posts"). I use a single store. When I ship the app, the "posts" entity is also defined but empty. When I update the data model I simply re-generate the whole reference store before shipping.
I see absolutely no reason to go for a cross store solution here.