i want to store some managed objects as to make searching later on easier, what is the best way to do that? (So that it survives exiting the app)
I am thinking user defaults (but im not sure if you can store managed objects like this)
Or some sort of cache?
SO, although I am not sure this is the best way to do it, here is how I fixed this issue. I was looking for a way to preload a list of results that would persist through launches.
To accomplish this I created an NSMangedObject, called it HistoryObject, and added a relationship (to-many) to the object I wanted to store. I added those objects to this object (basically an NSManagedObject array of objects), and retrieve this object whenever I want to load the subObjects...
Related
I want to ask for a safe way to clear subEntities in coredata.
I have my a many-to-many relationship like this: Product *<->* Product. Therefore, I've got to create a subEntity to hold some special values between (sortPosition, groupName.....).
So it's like this: Product *<->1 ProductSubEntity 1<->*Product.
When I download products from server's API, the easiest way to update correctly correspond to the server's result is:
Remove all child relationship ([self removeProductSubEntities:self.subEntities]).
Add sub from server's result.
Result: There'd be a lot of subEntity in coredata (which won't hold relationship to any product), and this might take storage/memory/cpu when CRUD (I think?). But I can't actual delete the subEntity (in case it's being hold reference to as an viewController's Object somewhere, and it might cause crash: access to a deleted object).
QUESTION:
How can I clear those sub entities (might occur sometimes) if:
No relationship to any product.
No actual reference from anywhere (any viewControllers or objects)???
P/S: I'm thinking of implement a batch delete when terminate app. Could that be consider a safe solution?
I don't consider this to be a datastore issue, rather a UI update issue. You should delete the objects from the datastore when you don't need them any more and you should update the UI accordingly.
1 thing you didn't mention is re-use. It's possible that your download may be an update to an existing item, which you could find and update, then life is easy all round. Arguably everything below still applies in this case though as your UI might not update to reflect changes and you may need to refresh the managed object.
For the UI update it's generally wise to observe the datastore for changes, usually with an NSFetchedResultsController. If you're doing this then your UI would automatically update itself with the changes.
If you're explicitly passing entity instances around then you should have some way to trigger an update explicitly, and exactly how that works depends on your UI. Generally speaking you'd be doing something like posting a UINotification to tell the system that the datastore changed and they need to re-validate their data objects. For the UI you shouldn't be showing now-dead objects to the user, and in your question where you talk about not deleting to avoid crashes, it's probably worse to allow the user to update invalid objects and just quietly not telling them that their updates won't be saved. When the notification is received you may want to pop a (some) controller(s) off the stack, or re-query the datastore for the new data to be displayed.
If for some reason you don't want to do the above, then yes, you can query for all of the entities with a nil relationship and then batch delete them. This should be done on a background thread just like data loading and I'd recommend doing it on app load instead of close (because you won't have so many view controllers loaded and the ones that are should all have only valid references now...).
I'm working on a quite large app on iOS. Up until now, I've been using CoreData like this:
Have a class, that have methods like -(NSArray*)getAllEntries, or -(void)saveEntry:(Entry *)entry, and Entry has a few properties like strings, dictionaries, arrays of other objects that might or might not be saved in CoreData, etc. Mostly, I init Entry with its default ctor, and set values to properties by fetching values from the NSManagedObject by using valueForKey: I get from the CD store.
I started coding like this because at the time I was new to obj-c and I come from a C++/Java background.
Now, I'm working on a new module in the app and want to do everything the obj-c way.
As I understood, if making the Entry object a subclass of NSManagedObject, I could only init it using [NSEntityDescription insertNewObjectForEntityForName:#"Entries" inManagedObjectContext:context];, which means it would be tied to the entity? The thing is, that I might want to for example init that object from the data that I pull from the internet and I might not want to save it to the persistent store. Or, I might want to fetch the object out of the store, edit the values, but not save it to the store. Everything would be fine (probably), but as I understand, if I call the save method on the context which was used to instantiate the object, the object will be saved to the store that I didn't want to be saved.
So now I'm a little confused on how should I continue doing this. Is my old way of doing Core Data Ok, or should I use the subclass of NSManagedObject and use some tricks that I don't know of yet? And if the latter, what are those tricks?
Link answers are discouraged, but you really want to read Apple's extensive documentation on Core Data. Specifically, google for "Creating and Modifying Custom Managed Objects".
(Currently found at this link.)
Using Parse for iOS, I modified the _User's table to have a field called "Friends" which is an array of pointers to other _Users (by the way, I also have other additional fields).
When I call PFUser.currentUser(), I don't see this friends field in the user object. So I call PFUser.currentUser().fetch() (because refresh method doesn't seem to exist anymore) and I finally have the friends field in my currentUser object.
However, as soon as I exit the app, this field is lost. It doesn't seem to be saved locally unlike all the other fields of the current user.
How am I supposed to force a refresh of the cached current user ?
According to parse.com itself and one of their posts, there is no other way to keep your user up-to-date:
saveEventually does not write through any caches at this time,
including the currentUser, if the app has been restarted. You'll need
to regularly call fetch to keep it up-to-date. We are aware that this
is inconvenient, and are looking into ways to make it work better for
you.
Are you sure that you want your user objects to contain a value that's an array like that? I obviously don't know your use application, but I would recommend using a PFRelation instead. It works just like an array, but the Parse Framework provides a bunch of additional functionality along with it.
As for your specific question it might have to deal with Parse. Maybe they don't automatically retrieve and save arrays that are on an object. That would be my guess because an array could contain who knows how much data in it. I still don't know why they wouldn't locally save that data after it's fetched.
My suggestion is probably a little over the top, but would most likely be the best outcome. Utilize a local database such as CoreData or even the ParseLocalDatastore. Then encapsulate the Parse framework to have your own User object where you can store the information, which can also maintain persistence via your database.
I am having an app where there is a search feature that does a network request. However uses the same model framework as the entire app.
This means that when the user searches for something I need to create managed objects from the found data, save them and display them. However this messes up old records with the user recent data.
I would ideally like to save the managed objects found in the search in a separate in-memory persistent store so it doesn't make disorder in the main data.
I haven't done something like this before so what is the best way to approach it?
Thank you!
As has been suggested by #stevesliva, you do not need to involve yourself into the complexities of maintaining multiple partially in-memory stores. The way to go here is to create a child context and fetch the online data into this context. Once you do not need the data any more, just discard the context.
If you decide to save the downloaded data, you can simply "push" the changes to the main context via save:. At that point you could make necessary adjustments to the data so they fit into the user data. Depending on your model, one feasible solution could be to create another attribute on one of the entities that marks linked objects as distinct from the user created objects.
I'm working on an app that allows the user to create a little comic from a photo. I've implemented CoreData so the user can save and reedit their comic. I've created two entities: ComicInfo and ComicDetails which have a relationship with one another (I did it this way from reading the Ray Wenderlich tutorial). So when the user saves a comic, I make a new ComicInfo NSManagedObject, store the name and thumbnail in it, then I create a ComicDetails NSManagedObject, store various attributes in that, and I store the ComicDetails in the ComicInfo and save.
I've created a UITableView that displays the thumbnails and names from all the ComicInfo objects to allow the user to select one so they can edit the comic.
What I'm wondering is, why did I separate this into two entities instead of just doing them in one? I'm assuming that when I load all of the ComicInfos from CoreData, that the ComicDetails will also be loaded into memory, or am I wrong about that? In a perfect world, I'd like it so only the ComicInfos are loaded when the UITableView is launched, then when the user selects one of the rows, the associated ComicDetails will then be loaded into memory. Is that not what's happening here?
The reason to have two entities is to get the behavior you're hoping for. In general when you do a Core Data fetch, only instances of the entity type you request are loaded into memory. Related objects are not immediately loaded. Instead, Core Data loads them automatically on demand.
In your case, if you fetch ComicInfos, only ComicInfos get loaded. But if you take one of those objects and access its details attribute, the related ComicDetails instance is automatically loaded, without needing to do another fetch. The related objects are only loaded when you ask for them. So, you're getting the behavior you want.
If you ever want to override this behavior, you can use setRelationshipKeyPathsForPrefetching: to force NSFetchRequest to load not only the objects you actually fetch, but also specific related objects as well.