Stop Core Data objects from auto-arranging - cocoa

I have a NSTableView and I binded my Array Controller to it. The Array Controller is binded to my Managed Object Context. Everything in the NSTableView works but the objects in my TableView rearranges randomly when I start up my app. For example, the order of [1,2,3] will suddenly change to [3,1,2] and this happens occasionally. I want it so that things stay in the order they were put when making them. How do I stop the rearranging?

The rows in the CoreData data store are not sorted! If you want to view them by creation date you need to add your own timestamp to every object and pass a sort descriptor to the fetch request.
Edit: If you are using SQLite as your CoreData store I recommend to have a look at the SQLite file. This will give you an idea on how CoreData works and explain why certain things (like unordered rows) are the way they are.
P.S. I use Base to inspect SQLite databases. It's not cheap but quite nice.

Related

Core data, bindings, NSArrayController and table views - how to generate a view of a core data context

I have a working system that lets me build a database containing instances of various entities , all linked together nicely.
Before I knew I would care, I came across a tutorial on using Core Data and bindings, and it went through a complete case where you get a table showing all the entities of some type with a column for each property. It showed both the UI side and the Data model side - not that I need the data model part at this point. Now, darned if I can find it. This is one of those things that is supposed to be easy, and requires virtually no code, but getting exactly the right connections in UIBuilder is not going to happen if I can't find instructions.
Also, I thought I came across an example of something like a query editor where the user could select which properties to sort on, which to match on, etc. Did I imagine that?
Anyone out there know where I can find such?
Sure, you can do this without code:
Add an array controller to your nib.
Bind or connect an outlet for its managed object context
Set the array controller to Entity mode, fill in the entity name, and select Prepares Content.
Bind your table view columns to array controller's arranged objects, and fill in the key name for the model key.
Regarding the query editor, open up the model, and on the Editor menu click Add Fetch Request.
I found at least a partial answer to the query editor question, in this apple tutorial. Not sure how far it will get me, as I prefer to write code where possible, since then I can leave a trail of comments.

CoreData and big tables

I have a Cocoa Mac application with a search field and a collection view bound to an sqlite table through CoreData. The table contains several hundred thousand records with text fields (name, place, ...) indexed by name. I'm using BEGINSWITH predicate in a search field binding to select a dozen of records for display in a collection view. Everything works fine, but the problem is that CoreData loads the whole table into memory at the first query request and only then does the necessary filtering of records for display which means considerable delay for the user.
Is there a way to set up CoreData so that the whole table does not load into memory? Ideally, I would like to fetch only the first 100 items from a range of alphabetically sorted records for every query in the search field.
On iOS, this would be achieved using a NSFetchedResultsController. The following question describes the Mac equivalent controllers (such as NSArrayController): NSFetchedResultsController Mac OSX Cocoa equivalent.
EDIT
As per my comment below, a NSFetchRequest should be created in conjunction with the array controller. This can then be configured with fetchLimit and fetchOffset to determine how many fetch results are returned.
Make sure that you have the fetch request set to fetch as faults only. That way only the objects whose attributes who are actively accessed will be fully loaded into memory.

Getting a unique identifier for each element of NSArrayController's content

I'm making a custom view that I want to be bindings/core data compatible and represent a collection of data (a la NSTableView)
Is there any way my view can refer to a specific subset of the elements in the collection (other than the current selection) after a change by the user?
A bit of context:
The view is going to display a number of user-moveable boxes in a 2D space. Each box corresponds to a record in the model. Several can be moved at once, and I can't rely on the delta value being the same for each box (so no adding a delta to each selected object).
I guess I'm looking for something like an id assigned to each element of the content array by NSArrayController, so that the view can associate that id with each box. My first thought was to use the the index in a content array, but this could be messed up by undo/redo. I could subclass NSArrayController and get it to auto-generate an id for each model item, but does cocoa already do something like this already? Feels like I might be missing something.
I should have mentioned that I originally tried keeping each of the content array's elements stored in the view (as Peter suggests), but had them stored as keys in an dictionary.
The objects in the view didn't match the keys in the dictionary, so I assumed this meant that NSArrayController changed the proxy objects it uses to stand for model objects.
However, it turned out that NSDictionary copies its keys, so it seems to be no good for situations where you want to associate a particular instance of an object with another.
NSMapTable is its more flexible cousin, and can be configured not to copy its keys.
Why not just refer to the objects themselves? You can keep them in a set or array, whichever is appropriate.
If you really need an identifier of some sort: What for? What are you going to do with it?

Core data: can NSFetchedResultsController fetch two different entities?

I am working on an iPhone app, and in a particular view I need to load two different entities: One that will populate a UITableView, and another that will populate a UITextView.
Is it possible to fetch both properties using a single NSFetchedResultsController?
Or do I need to use two different NSFetchedResultsControllers?
Any ideas on how to best approach this problem?
Each fetch request has only one entity and each fetched results controller has only one fetch. Therefore, you need separate controllers for each entity.
If you think about it, how would you make a predicate to fetch two logically separate entities?
You probably don't need two fetches at all. In most cases, you can fetch the entities that populate the table and then use a relationship for the entity of the selected row to populate something like a text view.
Best solution would be to refactor your Model and see if your 2 entities have something in common. You can make an abstract entity for the intersecting stuff, then inherit your 2 entities out of that. Perform the fetch on the abstract entity, and your fetch results controller should return mixed results.
As TechZen stated, the answer is no.
However, you can monitor the saves of the NSManagedObjectContext yourself and react to those saves. If you really do need to watch more than one entity (something that is far more common on the iPad than the iPhone) then add a NSNotification observer on the NSManagedObjectContextDidSaveNotification and look at the -userInfo of the NSNotification that comes back. You can then run predicates on against the results to determine if you need to update your display. That is what the NSFetchedResultsController is doing under the covers.
The quick answer is NO. But I found a creative answer.
In your tableViewController, make a search bar with how many scopes you have.
When different scope is selected, you can fetch different entities!
This works because I made an app like this!
Users would have easier time separating the two different data too!

Filter/Sort in the view or in the model?

Having a list of data object and something visual to represent each, where would you code the sorting/filtering logic? Why?
Edit : All the answers so far are good, but I forgot to add another constraint. What if I don't want to reconstruct the view each time?
The answer lies in the data. The model delivers the data. If all the data is in the view, the filtering and sorting can be contained within the view. If the data is chunked, the model must deliver the data and contain some of filtering/sorting (the view may still contain filtering/sorting as well).
The controller should not contain these functions, since it is a routing mechanism and should not have any idea of how to interpret the data.
Depends on the complexity of the sort/filter operation and whether the view control offers those services natively. If the view control offers filtering and it's simply reformatting the in-memory data then leave it in the view. If the sort/filter requires another trip to the data source then keep it all in the controller.
I would put in the sorting and filtering methods in the controller, and call these methods from the view.
Your View should only handle displaying the output. Put any filtering/sorting into your business logic and return it to the view.
I believe the sorting should be something separate. You should not sort in the model because you want to keep it as-is. Basically, a change in the model implies a re render of the view and you probably do not want that (if you want to animate a transition between the pre and post filter states, for example).
What I would suggest is that the model provides the data to create both a list of visual objects for the view and a sorter object. The sorter object would output a render list which would simply be a list of some identifier linked to the visual objects (index in objects list or other). The order in which the IDs appear represents the order of the sorting and any ID not in the render list is hidden. Every time the view receives a render list, it would update it's display.

Resources