Is there a memory issue regarding the number of items in the list I am displaying in my table view? If the user keeps adding items will the application eventually crash or something due to memory issues?
To answer your questions:
There's no black and white answer to this. To try my best to explain, think of UITableView as sort of like a visual data array. In fact, most people (myself included) use a source data object like an NSArray or an NSDictionary to provide the display data for a UITableView. All the memory limitations that would apply to these objects (arrays and dictionaries) apply to your UITableView, assuming your UITableView is set up properly and you're using the recommended techniques for reusing cells. What this boils down to is: Is it possible to have a very large UITableView? - Yes. How long though, this I don't know. I've created UITableViews with complex subclassed cells and 200 rows and they worked fine. It depends on how you set up the table and the data source you're using. Bear in mind again that the limitation is due to the data source. Have an extremely large array and eventually your device will throw a memory warning. As a best practice, use pagination. There are tonnes of tutorials online to enable paging on UITableViews. Lazy load your images (if any) if they are being downloaded.
Yes you can. You can do lots of amazing things if you're creative enough while subclassing UITableViewCells. Otherwise, you can use the standard UITableViewCell as well. There are two labels on there: The textLabel and the detailTextLabel. Use these two to display the data you want.
Your UITableViewDelegate has a didSelectRowAtIndexPath method which you can implement. As long as your view controller housing the UITableView is set to be it's delegate, it will respond to didSelectRowAtIndexPath.
Just empty the array you're using as a data source (bear in mind that your numberOfRowsInSection data source method MUST use the array count) and call reloadData on the UITableView
EDIT: The question got edited, so only point 1 from the above 4 points applies to the question :) The others are nice to know though
Nothing table-specific, but yes, you will run out.
The most important thing is probably to use dequeueReusableCellWithIdentifier: in your tableView:cellForRowAtIndexPath: delegate method. This basically cuts down memory usage to the number of visible cells (plus one being scrolled into view).
Related
I am aware that Apple is deprecating the use of NSCell in favour of NSView (see AppKit 10.10 release notes). It was previously recommended that NSCell be used for performance reasons when many controls were needed.
I have spent considerable time implementing a custom control that required many subViews and the performance using NSView-type subViews was not good. See related stackoverflow discussion What are the practical limits in terms of number of NSView-type instances you can have in a window? I was struggling with 1000-2000 in-memory objects (which doesn't seem a lot). What is the actual reason for this limitation?
One thing that confuses me on the above is View-based Cocoa NSTableViews. You can create tableViews with more than 1000-2000 cells and they don't seem to have poor loading and scrolling performance? If each of the cells is an NSView then how is this achieved?
If there are practical limits, then what are Apple thinking when they say they are deprecating usage of NSCell's? I am sure they are aware that some controls need a large number of subViews.
Further, an (probably outdated) Apple Developer Guide give the following explanation for the difference between NSView & NSCell which I need explained further:
"Because cells are lighter-weight than controls, in terms of inherited data and behavior, it is more efficient to use a multi-cell control rather than multiple controls."
Inherited data: this would surely only cause "bloat" if the data was being used => and it would only be used it you needed it?
Inherited behavior: methods that you don't use in a class/object surely can't cause any overhead ?
What is the real difference between the lightweight NSCell versus the heavyweight NSView other than that it just seems to be conventionally accepted?
(I would really like to know.)
A brief and incomplete answer:
NSCells are about drawing state, and not much else. NSViews must draw, but also must maintain and update all kinds of other information, such as their layout, responding to user input events, etc.
Consider the amount of calculation that must happen if you resize a view that contains many hundreds of subviews: every single subview position and size must be maintained according to the existing constraints for the view layout. That alone is quickly a very large amount of processing.
NSCells, in contrast, don't exist in a layout in that way. Their only job is to draw information in a given rectangle whenever asked to do so.
One thing that confuses me on the above is View-based Cocoa NSTableViews. You can create tableViews with more than 1000-2000 cells and they don't seem to have poor loading and scrolling performance? If each of the cells is an NSView then how is this achieved?
NSTableViews re-use views. The only views actually generated are those that are visible, plus maybe a row of views above and a row below the visible area. When scrolling the table, the object value associated with a given row of views is changed to that the views in the row will display different content
instead of the normal
dequeueReusableCellWithReuseIdentifier
This dequeueReusableCellWithReuseIdentifier:forIndexPath: requires us to register stuffs. Which is annoying.
The question does not ask why we bother dequeing cell at all. I know why. This question ask why we do not dequeue UICollectionView the way we dequeue UITableView
For performance reasons, a collection view's data source should generally reuse UICollectionViewCell objects when it assigns cells to items in its collectionView:cellForRowAtIndexPath: method. A collection view maintains a queue or list of UICollectionView objects that the data source has marked for reuse.
I've got an application which pulls back data from a database using Core Data, and displaying it in a custom cell in a UITableView, via an NSFetchedResultsController. I'd like to randomly insert a different type of custom cell every now and then (say, between every 10 and 20 cells), which will NOT get its data from that same database, and will be a different subclass of UITableViewCell.
I'm a little stumped on how I get in the middle of the NSFetchedResultsController and the UITableView Data Source methods. I have various options which allow the data that's pulled in to be sorted, filtered, etc., so I can't rely on using indexPath or anything like that.
What's the best approach to doing something like this? I know I can access fetchedObjects of the NSFetchedResultsController – is copying and modifying that the right way forward? Create, say, fetchedObjectWithInterstitialCells, and feed all of the Data Source and Delegate methods with the contents of that array?
Is there a better way / are there alternative ways to do it? I'll need to be able to retain the ability to sort / modify / filter the data from the database, while at all times keeping these interstitial cells at that same interval of randomly between every 10 and 20 cells.
I would consider one of the following three operations:
A: Insert objects into the database that are pulled along with the other data, but has properties to differentiate them enough to display the different subclass of the UITableViewCell. Probably the easiest way out, unless you have a very difficult datamodel.
B: If you can group your data from the data store into sections by using the sectionNameKeyPath-attribute on the NSFetchedResultsController, go for the NSFetchedResultsController + UITableViewDataSource-approach, and then return [[self.fetchedResultsController sections] count] + numberOfInterstitialCells; inside numberOfSectionsInTableView:.
In cellForRowAtIndexPath you would then need to override the section-info from the indexpath in order to switch between the right object from FetchedResultscontroller and your interstitial cells. This is probably a cumbersome and difficult way to do it, but if you are on iOS6 using parentContexts, the benefit from having implemented the NSFetchedResultsControllerDelegate is awesome
C: Fetch the objects with a normal fetchrequest and put them into a mutable array in which you insert your interstitial cells, before you load your view and feed your UITableViewDataSource with this array. As easy as option A, but you won't get the benefits of having the NSFetchedResults-Controller.
I'm working on optimizing the performance of my TableViews, and was wondering how expensive it is to create simple objects like a string or array within cellForRowAtIndexPath. The other option, of course, is to create the object as an ivar and set it each time a new cell gets loaded.
Which is better, creating a new object for each cell, or resetting the same object for each cell?
Note: I'm using these objects to do a number of different things, for example I'm creating a string to check the length of text I'm downloading from a server before passing it to the cell.
Creation of simple strings and arrays is not going to have an effect on the performance of your table. Creating views is expensive, and drawing them is also expensive - these are the areas you need to optimise for good scrolling.
Profile in instruments using the time profiler and core animation FPS instrument to be sure. This will highlight hotspots in your code, or alternatively give you a 60fps scroll rate*, in which case your work is done!
*on the device, of course
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.