I´m using a table view to display different types of items. The view controller for the table is always the same, ItemsViewController.
I have a menu with buttons for each type of item. Depending on what button the user clicks, a specific array of items must be used to populate the table view.
My solution:
Every item has an typeId property. When a type button is clicked, the following method is called:
[self.itemController createItemListForId:buttonPressed.typeId];
where buttonPressed is, well, the pressed menu button.
This is the implementation for createItemListForId:
-(void)createItemListForId:(int)theId{
for (Item *item in self.masterItemList){
if(item.typeId == theId){
[self.itemList addObject:item];
}
}
}
The masterItemList is popluted with all the items at initialization.
My ItemsViewController uses the itemList to populate the cells.
The problem is that itemList is empty when the table view appears, so something not working with this method.
Any ideas on how to get this to work?
Related
I'm building an app which which has built in with 2 different tabs. First tab is is "Home" which basically has a tableview with cells that configured from an api.(The api gets me country names for now)
Those cells also have a "Star" button which prints the data of the specific cell for now.
Second tab is "Saved" tab(SavedViewController), where I want to show the "starred" countries, using a tableview.
You can see the image below in order to get an idea for the app.
App simulation Image
The star button has a function in my CountriesTableViewCell. I'm using a saveButtonDelegate in order to let the SavedViewController know about an item is going to be saved. The code in CountriesTableViewCell for star button is as below.
#objc func buttonTapped() {
//If Button is selected fill the image. Else unfill it.
if !isSaveButtonSelected {
saveButton.setImage(UIImage(systemName: "star.fill"), for: .normal)
isSaveButtonSelected = true
saveButtonDelegate?.saveButtonClicked(with: countryData) //Checking if save button is clicked
}
}
countryData is the data that I get from the api, and this is the data I want to pass to SavedViewController.
struct CountryData: Codable {
let name : String
}
So on the SavedViewController, I'm handling the data using the SaveButtonProtocol conformance as below:
extension SavedViewController: SaveButtonProtocol {
func saveButtonClicked(with data: CountryData) {
countryDataArray.append(data)
print("saveButtonClicked")
print("countryData in savevc is \(countryDataArray)")
DispatchQueue.main.async {
self.countriesTableView.reloadData()
}
}
}
Whenever I click the star button on the first tab, this function is getting called on SavedViewController. So whenever I click to button, those print statements above work fine.
The problem is, whenever the star button is clicked, it should append the data of the current clicked cell to countryDataArray in SavedViewController. But the array is not populating as it should.
Let's say I pressed the first cell's star button, my print("countryData in savevc is (countryDataArray)") statement prints : ["Vatican City"], then I press the second cell's star button it only prints ["Ethiopia"] while it should print ["Vatican City", "Ethiopia"]
Why this issue is happening? My best guess is I'm delegating SavedViewController from the cell class so it behaves differently for every other cell. If that is the problem what should I do to solve it?
Many Thanks.
You should store your data in a shared (static array) object so you only have one source and add the saved indicator in your country struct so you do not rely on what is displayed in one view controller.
I have main UITableView with some Todos that are populated used an array of Observables:
// on viewDidLoad
self.todosViewModel.todos.asObservable()
.bind(to: tableView.rx.items(cellIdentifier: "TodoViewCell", cellType: TodoTableViewCell.self)) { (row, todo, cell) in
cell.status.image = todo.getStatusImage()
cell.title.text = todo.title.value
cell.todoDescription.text = todo.description.value
cell.dueDate.text = String(describing: Utilities.dateFormatter.string(from: todo.dueDate.value))
}.disposed(by: disposeBag)
On another screen I can add/edit the data and then, click "save" button to append a new todo or modify the one being edited. This works great, except that the tableView don't reload automatically, forcing me to call tableView.reloadData() on viewDidAppear, which is triggered when the other screen is dismissed.
So,
Is there a native way for me to reload a table automatically when then todosViewModel variable is updated?
EDIT:
If on the screen of edition of the todo I reassociate the todosViewModel's value property with the same value, it also works:
self.todosViewModel.todos.value = self.todosViewModel.todos.value
That's pretty ugly, but I only know how to reload a tableView using one of those ways.
When I append a new todo or reassociate a new value to the base todos it works. When I edit, no.
That's the whole point. For the UITableView to update, your todos have to emit when an item inside has been edited or you have to bind something from your todo within the cell (this way you cannot change hight of the cell but you can push some dynamic information onto the cell).
Another option would be to map some observable from todo to the index of the cell where it's presented and call UITableView.reloadRows to update your edited cell.
I would recommend you to take a look at RxDataSources examples.
I have created a UITableView that includes a UIImage, and two UILabels. This data is passed to a details view controller when the user selects the row. I have also successfully created a UIButton in the prototype cell that updates the text of one of the UILabels. I am unsuccessfully attempting to update this label within the array so this change is reflected on the details view controller. This is what I tried with no success:
#IBAction func updateTableData(_ sender: Any) {
grinds.removeAll()
grinds = createArray()
}
Here is a link to the repo: https://github.com/andrewTuzson/tableViewPractice
In the screenshot below, the left image displays the tableview after the first cell has been toggled to "Needs Work". The right image displays the details screen that is loaded after selecting the row.
How should I approach solving this?
If you want to update a tableViewCell upon the button click then, you should make the model array global to access it in click method and update what you want then reload the tableView either with delegate or NSNotificationCenter
--
in the custom class of the cell declare an integer property and in cellForRow set it like this
cell.index = indexpath.row
So the number of buttons on screen change with number of items in array from API.
I have a simple example, i have an array of integers and for each item in the array i am going to create a UIButton and add it to array of UIButton.
let array = [1,2,3,4]
var buttons: [UIButton] = []
for item in array {
let button = UIButton()
button.titleLabel?.text = "Button \(item)"
buttons.append(button)
}
print("Number of buttons: \(buttons.count)")
Based on your information you should not create a button for each item in the array you collect from an external API. Since you are using a collection view I would design a collection view cell with the appropriate properties. One of the properties should be a unique identifier. This standard collection view cell is the model for all your collection view cells, that represent your buttons.
Then use the collection view delegate method: collectionView(_:didSelectItemAt:) to react on a tap/press from the user. In this method the functionality that you use will be based on the unique identifier of your collection view cell.
There is no need to create a button in a collection view. The collection view already has all the functionality in its collection view item.
I have a table view in my profileViewController that display user's data such : first name, last name , birthday , gender...
I want to edit this table view by clicking in my custom edit button and i can after edit it by mouse and keyboard in ever selected row.
I have implemented a method :
-(IBAction)editTableView:(UIButton *)sender {
if ( sender == self.editButton) {
NSLog(#"Editing");
[super setEditing:TRUE];
[self.userTableView setEditing:TRUE];
self.editing = YES;
}
}
I have searched on the net but I find that edit table view means add or delete a row in this table view and my purpose is to can edit ever row selected by keyboard and mouse ...
A typical interface is this: The user taps on a cell, and you present a presented view controller where the user can edit the same data that appears in that cell. For example, if the cell contains a name label, the presented view controller contains a name text field. If the cell contains a gender label, the presented view controller contains a gender segmented control. The user edits, and then taps Cancel or Done. You dismiss the presented view controller. If the user tapped Done, you also save the user's changes into your data model and reload the data into the table.