As many of you may know, an NSTreeController bound to an outline view can display duplicates while presenting core data entities.
A temporary solution is to add 'parent == nil' to the predicates, but this only returns parent entities. If, for instance, a user is searching for a sub-entity, the requested sub-entity won't be displayed.
A (proposed) solution is to subclass NSTreeController and add a NSMutableSet variable, which keeps track of entities that are currently being displayed. This variable should be alloced on init, and released on dealloc.
When "fetchWithRequest:merge:error:" is called, the set should be emptied (I'm not sure whether this would be more efficient than releasing it and allocating it again). Everytime an entity is going to be added to display, check if the set contains it. If it doesn't, add it. Otherwise, find which is closer to the root (which is the subentity) and either skip it if its the subentity, or swap it with the previously included one.
I think there should be relatively little impact on performance (considering NSSet uses hashing). The problem I'm having is finding the correct method to override to add this behavior. Specifically, where NSTreeController processes fetched entities after "fetchWithRequest:merge:error:" is called.
Is it fair to say you're really looking for a way to filter the tree with a search term without losing the tree structure? The inherent problem (beyond forcing the tree controller to include the parent nodes of a search match) is that the parents may or may not actually match the search result, so it's confusing to display them.
I think yours is more a problem of UI, isn't it? In that case, the best approach (and one I've seen many well-known companies and independent developers take) is to display search results in a plain table. This way the results can be sorted by various attributes and you don't have to disable drag and drop in the outline view in search mode (to avoid the user trying to change the tree structure when only part of the tree is displayed out of context).
Expanding on Joshua's answer, I was able to implement Search Functionality into my own NSOutlineView, however it was limited to the root/parent objects in the view.
I think (like Joshua said) if you wanted to filter all objects you would have to display the results in a NSTableView.
Related
The UITableView can be used to create a list view if the at least the UITableViewDataSource is adopted by the relevant class. I have the below questions:
Why is it designed in such a way that based on the section and row , the controls are created through data source methods and given back to the UITableView instance. Why not provide all these information in UITableView instance with out using the UITableViewDataSource. What difference is it going to make?
EDIT1:
#hermann and #JOhn: You have mentioned that it breaks the MVC pattern. Let us assume I am creating a custom UITableView like control myself. I design it in such a way that I do not pass the data directly to the UITableView but instead I pass the relevant subviews that needs to be added in the rows and section and their relavant headers alone. I think this will not break the MVC..Am I correct? But still it has the problem that the current UITableView implementation style solves..the ability to reuse controls and images instead of bloating the memory usage.
First, doing so allows to stick on the MVC pattern. A UI object, meaning a view, should never directly communitcate with the model, wich is the business data. Plus it should not perform any business logic, which belongs to the controller.
Second, it is more flexible without the need of subclassing the UITableView object.
Third, the full concept is quite efficient from a performance and memory management point of view. Instead of loading all data upfront, that may be displied within a table, it can be fetched or calculated or whatever on a just in time "need to know now" basis.
Plus data containers, especially memory consuming once like images, can be released as soon as the data has been provided using the delegate/data source methods.
Of course, a subclass of UITableView could do the same in principle. I just doubt this would result in more maintainable code or even save any time or work resprectively.
If you don't want to stick with MVC, then feel free to subclassing the table view and hand all its data over in its init method or enable the table view subclass to load all that data from webservices or data bases or wherever it comes from.
And when you run into problems and get back to us searching for guidance, then be prepared for some nasty replies like "Why don't you stick to the established best practices or the MVC pattern?" ect.
In the event that your very table just displays some rather static values, such as if it just acts as menu for further navigation drill down etc. then this concept may look a bit rediculous. But it does not hurt either. And when it comes to more complex tasks of data providing then it certainly has its advantages.
Give it a chance. Give it a try!
For MVC you want to try to clearly separate what the model, controller, and views are responsible for doing. By allowing the view (tableview) to ask for the data from a delegate, the view can be create extremely generalized.
Using the delegate pattern, the controller can "stage" the data in anyway that is wants and then give it to tableView as the tableView needs it. The tableView doesn't care where the data comes, how it was transformed, what ADT is used, nothing. It is complete ignorant to where or what the data is. All it knows it should show this string at this location for this section and row.
I'm developing an app for iPad. I have a form (UIViewController) for adding new records (of type Person) to my sqlite3 database.
For updating (i.e. modifying) records, I was considering using the same UIViewController, but I want to know what's better: one UIViewController for adding and another for updating, or one UIViewController for both adding and updating?
It depends on the amount of overlap.
If updating a record presents all the same information as creating a record, then it will be less lines of code, and less duplication, thus easier to maintain if there is one view controller.
You could even have two different storyboard views using the same view controller. This will let you give a different look when creating or updating records. I think it's good to have a noticeable visual differences for different operations. It gives a visual clue to the user as to what operation they are currently performing.
On the other hand, if there are different business rules when updating records, or if there is a different workflow when creating a new record, then two view controllers may prevent lots of branching code reducing the cognitive complexity.
In this case, you may want to consider subclassing one view controller from the other.
The question is a little vague. Let me check my understanding:
You're writing code in Obj-C that involves a type called Person that has some information
You have a form by which a human fills out the information in type Person.
You then helpfully give that human an "updating" notice of some sort, so they know you're working hard, not hardly working.
Your question is whether you should use one UIViewController for the form and one for the updating notice, or use one that covers both cases, correct?
If that's your question, I'd answer that it's largely a matter of taste, but you probably don't need a whole new UIViewController for the update notice. I'm not even convinced you need a different view, never mind its controller. You can do it either way as you prefer, but I'd recommend the simplest option that does what you need.
At the moment I'm sticking around with the nstreecontroller that is backend with core data. My problem is that no rearrange get triggered if I edit a field or add a new row.
Structure:
NSTreeController that is configured with prepare content ON and uses lazy fetching ON. The controller is bound to appDelegate.managedObjectContext and to appDelegate.mySortDescriptor (which is a function that returns an array with a nssortdescriptor inside).
Outlineview that has his columns bound to treecontroller.arrangedObjects.name. The Outlineview is also in SourceList mode.
An entity called "Item" that has a one-to-many relationship (children) to Item and a one-to-one relationship (parent) to Item. And of course there is a field called "name" that holds the displayvalue.
two storages. One is only hold in memory and the default one. The temporary storage is used to set up the root entities (I don't want them to get stored because they're just "visual")
Until here everything is fine except for:
On launch the sortdescriptor get read in but not executed (I've to call myself the rearrange function)
no modification on the core data triggers the rearrange method
I already tried to solve the problem at me own with following results:
Removing "Uses lazy fetch" will solve the problem o_O but who wants that?!
Calling rearrange in outlineView:setObjectValue:forTableColumn:byItem: (outlineview datasource) will solve the problem. But I do not really understand why this gets called (I'm using coredata, so it shouldn't get called?). On the other hand, calling rearrange to often messes up the sorting again (Ex. if you save a cell which hasn't changed his value)
That's the reason why I told myself that you've to face the fact that you're doing something wrong :)
What I actually want to have is the following:
CoreData backend
Outlineview is always sorted (the user cannot change it)
Skipping the save of the root objects
Less work is always welcome
thanks a lot and best regards, matthieu riolo
PS: Hints are appreciated too
I have an NSArrayController bound to a property of an NSManagedObject subclass. The subclass is automatically generated by mogenerator (which creates a set property for the relationship).
The NSArrayController is bound to network.posts where 'posts' is a 1-M relationship. Note I am binding to 'posts' rather than the 'postsSet' mutableSet accessor generated by mogenerator.
The set represents a relationship with another entity. The array controller has a sort descriptor set and, when the window it is associated with opens, data is displayed in the correct sort order.
Then I add a new object by instantiating an entity and then adding it to the relationship.
The NSArrayController is correctly observing this change and the new object appears in arrangedObjects however, after the insert the sort order of arrangedObjects is lost and the records appear in a different order.
I have verified that the sort descriptor is still set correctly. The NSArrayController has autoRearrangeContent=YES. I've even tried manually calling -rearrangeObjects after the insert but the sort order remains wrong.
If I close the window and re-open the newly instantiated NSArrayController has the data with the correct sort order again. Until I do another insert.
My experience has been that NSArrayController has automatically kept the correct sort order when objects are added/removed but maybe that was a lucky coincidence?
I can't find any description of the correct behaviour in the Apple document so I've no idea what to expect, what might be going wrong (if anything), or - in either case - what I should do about it.
1) Given a sortDescriptor should NSArrayController be keeping arrangedObjects sorted after objects are inserted/removed from the underlying collection?
2) If so, what might prevent this from happening?
3) And, if not, what is the correct way to keep arrangedObjects sorted?
I'd be grateful for any help. It's not easy to provide useful source code in this situation since, in principle, there isn't any. But I'm happy to clarify and answer any follow-up questions.
Turn off lazy fetching. Not sure the reason but when the controller is being lazy it doesn't resort things when they are edited or added.
By what are you sorting? Core data does not support ordered collections. To preserve any kind of order, you have to add some sort of attribute (pun intended) and sort by it.
Behind the scenes, CD is using NSSet/NSMutableSet - not NSArray/NSMutableArray - for collections. That your objects come up in the same order more than once is entirely due to caching, not by CD maintaining your collection's order.
Update for Lion (10.7)
With regard to my "does not support ordered collections" statement: If you're targeting 10.7 and above in your application, [NSManagedObject now gives you ordered relationships.][1] Use -mutableOrderedSetValueForKey: and -mutableOrderedSetValueForKey: to set and retrieve NSOrderedSets. Yay!
Perhaps instead of binding the NSArrayController to your attributesSet (generated by mogenerator), you should instead bind to the underlying dynamic attributes property itself, which is created by Core Data framework? attributes stands for your relationship name.
Sorry if this seems like a silly question - I am an amateur when it comes to Objective-C and Cocoa and even less knowledgable when it comes to Core Data usage.
So here's the situation: I have an NSOutlineView that I've already populated with a few items manually with an NSTreeController. What I need to do now is take the items in one of my Core Data entities and append them to the NSOutlineView's current contents.
Obviously this is beyond the abilities of bindings, so it will need to be done programmatically. What should I do? I assume that I need to do a fetch and then iterate through the returned items, adding each to the outline view. Is this correct? If so, would anybody be able to show an example of how this is done?
Thanks!
Create an NSFetchRequest with an NSPredicate that gets only those whose "parent" is nil (the root/top-level objects). Sort them by some attribute that makes sense (as the fetch results will be an unordered collection - an NSSet). Then implement the NSOutlineViewDataSource to mix/mingle the information as you see fit as it's provided to the outline.
Caution: It's best to cache your results, observing the context for changes and refreshing the cache on each change.