I have table view with multiple different cells, and one of the cells depends on property of another one. I.e. I have FirstCell, which has dynamic property count, and I have SecondCell, which contains several UITextFields. I want the number of these UITextFields to match the count property. How can I get count property from FirstCell considering that this property can be changed?
I.g. FirstCell contains count = 3, SecondCell shows three UITextFields. Property count changes to value 4 and another one UITextField appears in SecondCell.
The value of count should be in your data model. You add an observer, or put code into the setter, so when the value of count is changed, the two cells depending on it (the one displaying count, and the one showing the text fields) are both reloaded; that's reloadCellAtIndexPaths or something like that from memory.
Obviously the code that loads cells must be written correctly, and code changing count in the first cell must change the model property.
Thinks like this should be managed by the UI(Table)ViewController. The view controller should be notified when the text field changes (for example using target-action) and then update the data source and reload the relevant cells.
Related
I'd like to get every data that is within all cells in one tableview which is quite a long list.
I'm looking for an approach on how to retrieve everything including those hidden in view, which I know the views are reused. I think some of you might have experienced this problem before, what are your approach on this?
I've tried
let cells = self.tableView.visibleCells
then looping into every cell and saving each data to an array but it is not effective in getting those that aren't part of the view or hidden. Is there a way to get over this?
In cellForRowAtIndexPath, YOU are telling the table what is in each cell. So why would you turn around and ask the table what's in each cell? If the user puts "Hello" in your first cell, then scrolls the table enough to push that first cell out of view, then when the user scrolls back to the top, YOU are the one telling it to put "Hello" back in that first cell. YOU own the data source, not the table.
You need a data source. That can be "empty" at first, maybe an array of empty strings if that's what you want (each index in the array could map to a table row for example). But then, as the user interacts with the text fields in the cells, you need to update that data source with the text they entered.
You should use that data source as your source for the cellForRowAtIndex method. That way you can handle populating the cells when they are requested by the table, and you also know all the data when the user is done.
Why not just update the model each time the user taps a key when editing a textfield? You could create a protocol for that cell subclass and make your view controller the delegate for each cell. As long as cells are guaranteed to stay on the screen while you're typing (you'll get some weird behaviors if not) the cell can send a message to the view controller or whatever you hook it up to telling it what new value to store. Then everything is already stored for you when you need the full list, and you don't have to interact with the tableview.
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 have a custom view that exists in a cell in a tableview. The view is called bulletRow and it is a series of bullets that can be filled in or emptied when a user taps on them. Each cell in my tableview contains some bulletRows and I need to save them when the user taps on them. I have considered using Core Data, but I don't need them to persist when the app is shut down, I only need it to exist when the user scrolls past the dequeueing point.
Here is my situation right now: The default state for bulletRows is to have 5 dots, all of them empty. When a user taps on them they become filled. If the user scrolls down however, they get reset back to being empty. How can I save the state of the bulletRows?
The bulletRows have a property called numberOfFilledCircles which can be set at anytime to change the amount of filled in circles. This is all done in Swift as well.
In general, you should use something, such as an array, to hold the state of your table. The cells in your table should reflect that state, and update that state when selected.
You might start with an array of integers in your table view controller, like this:
var numberOfFilledCircles = [Int]()
Use the number of items in your array to determine how many rows to display in your table, by returning numberOfFilledCircles.count from your numberOfRowsInSection method.
You can populate the array in viewDidLoad. If you're hardcoding the rows, you can repeat this statement for as many rows you want:
numberOfFilledCircles.append(0)
Each Int in the array holds the value representing how many circles are filled (initialize to 0).
In your cellForRowAtIndexPath, use the appropriate value from your array when constructing your cell. For example, if your cell had a UILabel called numberOfFilledCircles, you would do this:
cell.numberOfFilledCircles.text = String(numberOfFilledCircles[indexPath.row])
Finally, in your didSelectRowAtIndexPath, update the array with the number of circles you want filled in:
numberOfFilledCircles[indexPath.row] = //whatever you want
The issue here is that the UI is not the model.
When the ui elements are pressed, you should send an action to the underlying model to update its state, and when cells are dequeued you should restore the checkbox state from the appropriate model element.
When I add objects to my datasource, I am not able to see the added objects in my collectionview.
I am able to see in the numberOfItemsForSection increment in value, but the corresponding cells do not display the objects. The indexpath.row does not exceed its original value that I set before.
HALP.
I have a view in iOS (iPhone) that have multiple components, organized in sort of a stack way (one in top of the next). Those are user account properties, some could be blank.
So, I have in my view the components layout like this:
UITextField1 (Name)
UITextField2 (Location)
UITextField3 (Age)
UITextView1 (Bio)
UITableView (user entries).
Some of the fields could be blank. Instead of having blank spaces for the blank fields I would like the next field to move upper.
This is like this question of flowlayout: What is the best/easiest way to create 'flow layout' type layout in iOS.
I can only see two ways of dealing with this:
Creating a function that traverse all the UIViews and determines which ones are blank and move the following upper.
Creating a UITableView and use different cell heights for cells whose content is empty.
Ideally there would be a component, but I cannot find it (basically some sort of stack/flow layout).
Anyways, I believe that I am going to implement the option #1 above, but I don't know if there is an "standard" way of accomplishing this (I honestly don't even know the proper term to look for this feature).
Thanks.
I would lean more in the direction of your second choice by using a UITableView but not the way you propose.
This would be my approach using a UITableView:
Create a UITableViewCell (or custom cell) for each one of my
components and assign a tag value to each, we'll use these later. You can do this in viewDidLoad.
Add code in numberOfRowsInSection to check to see which fields have
data values present. Return the total count of the number of fields
with data values
In cellForRowAtIndexPath again, check if data exists for that field
If so, check to see if the cell created in step one has already been created or not (if not, create)
If not, increment a counter of some sort to increase your tag value and find the next field that has a value. Once found, use that "tag/index" number to "return" the proper cell.
In the end, you have a UITableView only displaying the fields with data.