I have drawn my tableView in storyBoard with static cells and multiple sections. 6 sections each has proper number of static cells. In code, in MyTableViewController I do not implement any of the datasource or delegate methods, which logically means I do not have my model in code, the array or whatever that dataSource methods will use to populate number of sections or number of rows in a section. My question is: is it possible to insert a row to any of the sections?
I read a lot of stack questions. All of them is based on having a model array or dictionary that plays its role in dataSource methods to construct the table.
I have my table already constructed in storyBoard. I can get my number of sections with tableView.numberofSections() for example. Which means the model is stored somewhere for sure. I just need a proper method to get access to that model.
There is a reason the UITableView works the way it does with the datasource protocol. It allows iOS to use just what is needed to display on the screen at any given time as you scroll through the table, making it very efficient. Without implementing the required methods, iOS will not know how to rebuild the cell if you scroll it off the screen and then back on.
If you don't need that complexity (and really, it isn't complex and you can implement the required methods in less time than it is taking me to respond), you could use a UIStackView inside of a UIScrollView. It would allow you to simply add a set of UI components vertically down the screen, complete with scrolling.
Can you explain why you don't want to implement the UITableViewDataSource protocol?
Related
I have a main ViewController, MainViewController that contains a number of views along with a TableView.
Each row (i.e. tableViewCell) contains different content from different sources/views etc. A number of those rows in the tableView, in turn, contain a CollectionView called SettingsCollectionView. In the tableView's cellForRowAt method, I initialize the SettingsCollectionView for that tableViewCell and also pass it the respective data which that CollectionView subclass uses as its data source. So for example:
tableView row 0 - contains generic content
tableView row 1 - settingsCollectionViewA : SettingsCollectionView as well as a struct OriginalDataA
tableView row 2 - contains generic content
tableView row 3 - settingsCollectionViewB : SettingsCollectionView as well as a struct OriginalDataB
tableView row 4 - settingsCollectionViewC : SettingsCollectionViewas well as a struct OriginalDataC
tableView row 5 - contains generic content
When I initialize settingsCollectionViewA with OriginalDataA, I have a setter in that CollectionView that then sets up the local data under LocalDataA. This allows me to ensure I have the original and the working copy of the data based on the user making changes etc. Any time I call the OriginalDataA variable from the MainViewController, a getter in settingsCollectionViewA does some cleaning up of the data etc. so I can then do what I want with it in the MainViewController.
That part all works well except if those tableView cells are dequeued, when they reappear, I get back the original state for that tableViewCell and in turn collectionView rather than the state the user left it in.
I realize this is because each SettingsCollectionView class is working its own local copy of OriginalDataA, OriginalDataB etc. and appreciate I can just update the original data but then that creates other complexities - like the cleanness of current 'standalone' code built for the SettingsCollectionView subclass as well as the complexity of original vs. updated data. That's why I am stuck on a better programming approach...
Apologies, this might seem like a basic question but I'm new to programming and all the examples etc. I can find all speak to more simple scenarios rather than what I'm trying to do.
I haven't included the code because it's got a whole lot of other content and functionality that I think just confuses the concept outlined above.
Any help would be greatly appreciated.
Create a class that holds each of your data structs:
class MyDataModel {
var dataA: DataA
var dataB: DataB
var dataC: DataC
}
Then you create an instance of MyDataModel and hold a reference to it in a property of your view controller. Pass this same instance to your table view cells. Since it is a class and therefore a reference type, changes made by the cell will actually be made in this one instance.
Consider you have SettingsCollectionViewA which shows originalDataA. CollectionView displays the data what you provide in cellforrowatindex method. Collection view cells reuse memory every time. Only visible cells stays in the memory at any point of time. So user modified data will not be stored explicitly unless you modify the originalDataA.
I want to loop through a TableView and extract the text from all the selected rows. I suppose I "could" create and maintain a special array that is updated every time a row is selected/deselected using the didSelect/didDeselectRowAtIndexPath methods. But creating a separate array seems like an extra step. Is there no way to let the TableView itself serve as the array and then simply loop through it and get the selected rows? What would the code look like? I'm new to Swift, so this might be a silly question.
Part of the problem is that cells are supposed to be reused, and when used this way it is not possible to loop through them all. You could get around this by using a unique reuse identifier for each cell, such as the indexPath itself or some underlying unique id in your model. Then, you could indeed loop through all cells and retrieve whatever state you desired from each.
You would, however, find your application crushed under the weight of too many cells being instantiated and kept in memory. If you don't have many cells you won't be killed, but try it with a big data set and your app will enjoy a very quick death.
It is far more efficient to store one array with a bunch of id's than a large number of memory-intensive UITableViewCells.
As mentioned in comments, you should work with underlying datasource, not the table itself.
For example if your table shows rows from Array, it is way more faster to retrieve strings directly from that array than creating UITableViewCells and get strings from them.
Get indices of selected rows using UITableView's property indexPathsForSelectedRows.
Query datasource for each row.
As has been said the tableview only handles displaying, your datasource is what powers the data shown if you think about it.
Plus as said before the tableview dequeues cells as they scroll on and off the screen.
The best way to achieve what you want is to add a property to your datasource for each element that will allow you to filter out the select properties easily.
How are you storing the state for each selected cell currently? As this is the same functionally you would use to be able to generate your selected text array.
I need to display a table with in my iPhone app:
neither the number of cells nor the contents are known at compile time, but only at run time.
Views for each cell may differ, one cell has textField and another may have some other view control.
Should I consider Static or prototype cells?
Should I consider tableViewController or viewController with tableview in it?
Any thing I need to consider before I start coding? Thanks in advance
For The issue of dynamic Number of cell at Run time, you can call reload data for table view at any time you have the data source ready.
Prototype Cells should be used with no problem.
Simple Table View will be sufficient for the task.
You have to make cell, either in code or in storyboard, for each type of cell you want, 1 table View can have multiple types of prototype cells, Just name them differently and then make the objects of only the specific cell of which the data is best suited.
It is not that difficult but do handle the data source with extreme care.
Should I consider Static or prototype cells?
If you know all possible subview combinations that your cells might need to display the data appropriately, and they are relatively few, make one prototype for each. for example:
One text field,
Two labels,
One image view and a label,
...etc.
Otherwise, just use the plain-vanilla UITableViewCell (no subclassing) and remove/add subviews at runtime when reusing them (that is, inside the method -tableView:cellForRowAtIndexPath:).
Should I consider tableViewController or viewController with tableview
in it?
The only reason I would choose UIViewController + UITableView over UITableViewController is if -for example- I needed the table view to only take up part of the main view's bounds/screen, and display some other subview in the remainder. Otherwise, you get so much "for free" with UITableViewController that there's just no point in implementing all of that from scratch.
You have to choose prototype cell, u can create different types of cell depending upon your requirement.Any think ok for u, u can create tableview controller or view controller.
I've got a static TableView that now needs to become a dynamic TableView, because other views need to be placed around the ViewController, and this can not be done using containers in my case.
The question is: how do I efficiently convert the table view from static to dynamic?
I'm aware of having to change the inheritance from UITableView to UIViewController and add the plus the delegate methods.
But how about all of the Table-Sections: I have 3 sections with 6 types of cell in the static table. Do I really need to subclass UITableViewCell for all of these cell-types and deal with everything manually, or is there a more clever way to do this?
You really can't just convert between the two. By merely implementing some of the tables delegate methods, like cellForRowAtIndexPath:, you loose your static content. That being said, the table should be dynamic the entire time. This way, you can define logic to determine whether or not it should show the content that you originally added statically, or the new dynamic content.
Additionally, you don't need a view controller to implement the delegate/datasource methods. If you already have a subclass of UITableView, that's fine. You can set it as its own delegate/datasource, and implement those methods within the subclass.
And to answer your last question, no there really isn't a better way to do that. I recommend that you create one base class that subclasses UITableViewCell that implements everything that the cells will share, and then implement the individual changes in subclasses of this base class. Using multiple cell subclasses in a table view sounds a lot worse then it is.
I have a UITableView that collects data from a database. What I would like to know is if there is some way I can iterate in the UITableView collection and check the values of the cell? The reason I ask is because I would like to update each cell based on the current value that it has (change font, size, color, etc.). I've seen in another SO post regarding this topic, but since the cells are already created and their values are changed it is a bit harder for me. I was thinking of iterating through the UITableView before I call reloadData, but any other suggestions are welcome.
You should not iterate over the cells of UITableView, because some of them (in fact, most of them) may not be present until you request them. UITableView aggressively recycles its cells, so if a cell is not visible, it is very likely that you would be creating it from scratch only to put it back into recycle queue moments later.
Changing your model and calling reloadData the way your post suggests would be the right solution. iOS will ensure that it runs the update in a smallest number of CPU cycles possible, so you do not need to worry about the cells that are already created. This is also the easiest approach in terms of your coding effort.
A table view is for displaying data. The properties of your table cells should only be written to, not read from. The appropriate way of handling this situation would be to update your underlying model objects -- the objects that you use to populate the table view -- as the data changes, and then reload the affected rows.
The issue you'll encounter is that UITableView reuses table cells. Once a table cell scrolls off the screen, it's quite likely that the table view will reuse the same cell to display a different row.
This means it's fundamentally not possible to iterate over the table cells. When you need to refresh a row because its data has changed, you should call reloadRowsAtIndexPaths:withRowAnimation: (or reloadData if all rows have changed) and if the row is visible on screen, UITableView will call your data source methods and give you an opportunity to configure the cell for display.