How to use Apple's TableViewUpdates collapsable table view with Core Data and NSFetchedResultsController? - cocoa-touch

I'm trying to use Apple's sample project with expand/collapse UITableView sections https://developer.apple.com/Library/ios/samplecode/TableViewUpdates/Introduction/Intro.html
The problem is that I'm trying to use it with CoreData NSFetchedResultsController, and I don't know how to change Apple's code to work with it.

The simple, if not very pleasant, answer is to store the expanded / collapsed status into the Core Data store and then use a predicate with the FRC request so you can change the store contents and it will automatically update the table.
Alternative could be to mutate the data you get from the FRC when the table view requests info from the delegate, which is also messy.
Depending on your data you could use multiple FRCs, one for each section, though this may not be very extensible.

Related

Issue in lazy loading the table view

I am badly struck in a issue where I am trying to populate the nestableview lazily. Below is my approach.
I have created a custom class PRIList where it has an instance of array to manage the models.
I have bound the priList.items to the array controller in the xib where items is not an instance in PRIList but to support lazy loading I have implemented the methods countOfItems and objectInItemsAtIndex:.
Initialy when I populate the PRIList I populate few objects (say 50) with valid objects and rest with the faulty objects. In the objectInItemsAtIndex I check if the item at particular index is valid or faulty. If it is faulty I fetch next set of 50 objects.
What I understand is NSArrayController calls the method objectInItemsAtIndex for only the visible rows in the table view. But the problem here is as soon as set the PRIList the objectInItemsAtIndex method is called for all the objects. This is even called when some selection is changed in table view (the stack trace shows this method is called from [_NSModelObservingTracker startObservingModelObjectAtReferenceIndex])
Basically I want to fetch the records whenever the user scrolls down in the table view.
I followed the same approach in a different project in Lion. It worked there. Currently I am in Mavericks.
I tried overriding the isCompatibleWithResponsiveScrolling in the custom table view and returned it to NO. Still no luck.
Any help is very much appreciated.
First, have you assigned or bound the sort descriptors of the array controller? Or set any columns to automatically generate sort descriptors? (I'm not sure that latter is relevant. It depends on whether the column is sorted by default.)
In any case, if the array controller feels the need to sort the objects in order to arrange the objects, then it will need to load all of the contents. I was under the impression that it always does so, anyway, although you report that it works.
For an issue like this, I'd recommend that you go for full manual control. That means not using bindings or an array controller. Use a data source.

Objective-C: Creating a file purely for holding variables

I would like to add a file to my project, who's sole purpose would be to hold an array. I would then #import this file wherever I need to add/get from the array.
My problem is that when I create a new file (I'm using Xcode 4), I'm not sure what type of template to choose, and then what subclass to choose.
My reason for doing all of this is because I have a SplitView-Based app, and one of the views has a textfield, where I am trying to output data. My problem is that whenever I switch to a different view and then switch back, only the most recent entry is there. I am not 100% why that is but I suspect it is because when I switch to a different view, the current view is forgotten about, along with the variables in it.
This is not a good way to do it. There are many ways to do what you want: prepareForSegue: if you are using storyboards, delegation, instantiating your viewcontroller in code and setting a property in the header-file..those are just a few ways.
The way you are proposing is a slippery slope to bad Objective-C code and is only going to cause you more headaches in the future. Take the time to learn to do it right.
Check out this to get you thinking in the right direction.
How you save your data doesn't appear to be your problem. Take a look at the MVC design pattern and how view controllers implement it. They often rely on a dataSource protocol, which links the data from a "Model" to your "View" in a logical way to achieve your intended purpose.
The view controller should then be able to assign a delegate (usually itself (self) to keep the view populated with the correct data, whether the view gets unloaded or not.
If your view controller doesn't refer to a data source or a corresponding protocol, it would still be worth your time to see how you might take advantage of that design pattern. It will pay off in the long run to know this.
Instead of saving variables to a text file, you should consider using NSUserdefaults instead.
But I don't think that's the real solution to your problem, just wanted you know that there are other ways than saving stuff to a text file.

Does setting the text of a simple text label go against MVC?

In MVC the View shouldn't hold it's data. However I know in Objective-c you do: [textField setString:#"hello"];, that string is then retained by the text field. The same applies for the textField's font and text colour, etc.
However a UITableView uses a datasource to ask a controller for it's data, it's then up to the controller to reload the table view. But it also stores some data itself, like background colour.
I can understand a reason as to why a UITextView doesn't use a data source the code would become much more lengthy, if every property had to be a method. But why use a data source in some cases and not others, why not just set an array of UITableViewCells (I know that this means cells could not be reused and so it would use more memory, but what other design reason is there), for the UITableView to display?
And when creating you own objects how do you know when to just store a small amount of generic data (e.g. the string a textview displays can only be a string, but any the string itself can be anything)in a view, or use a datasource?
MVC is a pattern, not an edict. Let the view do the work. Some coupling is just going to happen. Follow the guidelines of the pattern, and bend it to the style and desires of your developers and organization.
I'm not familiar with objective-c's mvc framework, but I think I understand the question.
Basically, you don't want the view doing anything with the datasource backend, that is, anything having to do with the plumbing of accessing the DB.
But its ok for the view to have access and use the data itself. That is the M part of MVC. The model gets passed around. The view knows how to display it. The controller knows how to do the business logic to it (including interacting with backend systems like the data access layer).
In the case of data grid, it has to hit the backend to get the data, so it has to rely on the controller.
Ideally, the view knows only about display related information (like the background color). The whole idea being separation of concerns. You want the view to handle just its part of things, like-wise the controller. Then you can modify them independently of each-other.
As for the specifics of the datasource (versus an array), grids tend to be complex. Maybe that is handling paging or other niceties. In this case, I don't think its so much the separation of layers (since an array could just as easily be the model), but handling more functionality.
I'm not sure what you mean re 'storing' small amounts of data in the view. The view should tend to deal with 'view stuff'.

Adding data to a scrollview/table

I have an NSCrollView that contains an NSTableView. It has 3 columns and 4 rows. I have 4 NSStrings with content that I need to copy into the scrollview.
Using Xcode 4 I tried connecting the table or the NSTextFieldCell and then adding the text via
[_Cell1 setStringValue:MyString];
But nothing happens. It doesn't get updated.
Any way to do this?
Thank you.
EDIT:
I found the following answer to a similar question. I still am confused but after reading Apple's example about bindings I can only say that this does not make any sense, so much code to achieve something so simple. That's the problem with everything being an object and with OOP in general.
Any simple samples out there? I don't even know how to start setting this or connecting the gazillion things you need to connect to start working with this
You should use the NSTableViewDelegate. That's a set of methods the NSTableView calls to get the data that it should display. You just have to declare the delegate object of the tableview.
Delegate Protocol
NSTableView Tutorial
Unfortunately, you can't "add" or "set" the content of a table view. Like most view objects, a table view doesn't store content; it depends on a controller to provide content when it needs it.
There are two options:
Data source: simplest, easiest to understand
Binding to an array controller: harder to understand, but less work to implement
The best Apple resource on the subject: Populating Cell-Based Table Views from the Table View Programming Guide. If you're struggling, I suggest you start with the data source option. It'll be just a few lines of code, and you can adapt the simple samples from that document.
To populate the table, you need to implement these two methods:
– numberOfRowsInTableView:
– tableView:objectValueForTableColumn:row:
And to change the data, you'll need to implement one more:
- tableView:setObjectValue:forTableColumn:row:
You'll need to set your controller as the data source for the table view in interface builder. And the correct protocol for this is NSTableViewDataSource, not NSTableViewDelegate.
You could use an NSArrayController and bind the table columns' value bindings to the array controller's arranged objects. Then add the values you want to display to the array controller.

NSTableViewDataSource or NSArrayController?

I need to load data dynamically as a user scrolls through an NSTableView. For example, the table might display 50 rows, and as it scrolls further I need to fetch more data from the network. The number of of objects/rows is known beforehand, so I want the table to have the right number of rows from the start, but showing empty cells while data is loading.
I'm using Core Data so it's easy to connect the table to my model using bindings. This would also take care of cells being updated as data comes in and is parsed. I've tried to figure out how I could do this by subclassing NSArrayController but from what I can tell there is no information flowing from the table to the controller about which rows actually need data. Therefore, I'm thinking of implementing NSTableViewDataSource instead, where I can easily check if the table has scrolled beyond the rows for which data is available. On the other hand, I don't know if I will get cells automatically updating as easily with this solution.
In case anyone comes across this, here's my own answer:
Yes, you need to implement NSTableViewDataSource on a controller, observe changes on the data and call reloadData manually on the table when changes occur. The main reason for doing this is that you can defer loading of data until it's actually needed (when the table view scrolls). Using the data source protocol keeps you informed of which indexes are requested.