I've run into a bit of an issue with NSTableView. The problem is that the table view is requesting data too early (it immediately requests the data from the controller), as in, the data is not there when the table view asks for it. Other methods, which gather the data to be shown in the table view haven't finished executing by the time NSTableView requests the data.
Hope that makes some kind of sense! I'm using Objective-C and doing mac dev (not iphone) btw.
Anyway, is there any way around this?
Thanks in advance.
The NSTableView is asking for the data likely because you have told it that there are say 20 rows of data. Once it knows there are 20 rows, it will start asking for it.
If you are using the NSTableView data source Delegate, its easy, just return 0 for the number of rows until everything is ready - then return the number of rows that there are.
IE you need these calls in the delegate:
– numberOfRowsInTableView:
– tableView:objectValueForTableColumn:row:
If you are not using the NSTableViewDataSource, and have wired up the controller in Interface Builder, then you will have to somehow only give the controller the data when its all ready.
Sounds like you're populating the table view asynchronously? If so you could call reloadData or reloadDataForRowIndexes:columnIndexes: on your table view in the method that handles the response to refresh the table view once the data has loaded.
Related
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.
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.
I'm really having trouble getting a Cocoa Table View cell to send action messages.
At the most basic level, in IB there is an action assigned for the NSTextViewCell object, and after editing and pressing Return nothing happens.
So I have an IBOutlet hooked up to the NSTextViewCell, and have been experimenting with NSActionCell messages to it. But the Table View seems to pretty much just ignore them.
I've also tried subclassing NSTextViewCell, but the methods I'm seeing all look like they want to pass values to the object from somewhere, not return a value from inside the object to configure its behavior.
I'm pretty new to programming and Cocoa -- can someone explain each thing that needs to be overridden and how and where to do it?
AFAIK, the cells in an NSTableView won't send action messages out to your application, they're sent to the NSTableView so it can update its data. NSTableView itself tries to be pretty clever and update your data directly, rather than just telling you something changed, so depending on what you're trying to do and what the data source for the table is, you have a few options.
If you're using an NSTableViewDataSource object to populate the table, it's simple; just implement tableView:setObjectValue:forTableColumn:row: and the NSTableView will call that every time something is edited.
If you're using Cocoa data binding (for example, using an NSArrayController to bind an array of objects to the table,) then as long as everything is wired up correctly, the data should just automagically get updated in the source objects when the table is edited. If you need to take special action, then you can do whatever you need to in the property setter of your data class.
I haven't tried it yet, but could work...
NSCell *cellYouWant = [tableView preparedCellAtColumn:tableView.clickedColumn row:tableView.clickedRow];
I've an NSTableView that uses the controller object for the NIB being displayed as the data source. I implement the NSTableView informal protocol.
This NSTableView gets its values from Core Data. I startup the application, load all values I have in XML and then display them.
My problem is, the NSTableView doesn't seem to add any new rows to the end of the table. If I start the application with no values in permanent storage and add another one (adding values works as I can see them being saved to XML), the table view simply ignores the new value.
If I add a value I know will go to the end of the table (the contents are organized alphabetically), I won't see the new value.
If I and a value that I know won't go to the end of the table, the value will be added, I will see it on the table, but the last value on the table will be pushed out and disappear.
I've noticed that - (int)numberOfRowsInTableView:(NSTableView *)tv is only being called when the application starts up and not when I do [tableView reloadData]. What causes this event to be fired? I tried firing it by hand before calling reloadData on the tableView but doesn't seem to work.
Any ideas to what might be causing this?
Has anyone encountered something like this? Any clues to what might be?
Alex's comment made me review the code, specifically bindings in Interface Builder. Turns out I had set the bindings between the table and my controller object and implemented the NSTableDataSource.
I've removed all bindings and only implement the NSTableDataSource protocol.
I have a UITableView that show a long list of data. Use sections and follow the sugestion of How to solve slow scrolling in UITableView .
The flow is load a main UITableView & push a second selecting a row from there.
However, with 3000 items take 11 seconds to show. I suspect first from the load of the records from sqlite (I preload the first 200). So I cut it to only 50.
However, no matter if I preload only 1 or 500, the time is the same.
The view is made from IB and all is opaque.
I run out of ideas in how detect the problem. I run the Instruments tool but not know what to look.
Also, when the user select a cell from the previous UITable, no visual feedback is show (ie: the cell not turn selected) for a while so he thinks he not select it and try several times. Is related to this problem.
What to do?
NOTE: The problem is only in the actual device:
iPod Touch 2d generation
Using fmdb as sqlite api
Doing the caching in viewDidLoad
Using NSDictionary for the caching
Using a NSAutoreleasePool for the caching part.
Only caching the row ID & mac 4 fields necesary to show the cell data
UIView made with interface builder, SDK 2.2.1
Instruments say I use 2.5 MB in the device
The -[FMResultSet next] call can be a very expensive call to make, depending on the data that's getting loaded. It'd during this call that sqlite is actually going to the database, finding the next row to return, and giving you back the appropriate fields. It's not just an enumerator.
You might want to consider pre-caching all of the data before actually displaying the table. This means that you would do all of your FMDB calls before the table gets shown on the screen.
If that takes too long, you might want to show the tableview with its initial rows, and then use NSOperations or just a second thread to load the data in the background and cache it that way.
Without seeing any code, I think I would be inclined to think that you need to index you tables.
You should see an enormous speed up by adding an index on the attributes you query on. You can do this by using the CREATE INDEX SQL command.