Reputation: 4023
I have a delegate method that passes an object from a detail view controller to a master view controller, which is a table view controller. The object is then used to update data for the table view:
var filters = [Filter]()
func didSelectFilter(selectedFilter: Filter) {
// finds the relevant data from the array and updates it
for case var filter in filters where filter.title == selectedFilter.title {
filter.setting = selectedFilter.setting
}
tableview.reloadData()
}
I'm able to confirm that the object is being passed properly. The object is as follows:
struct Filter {
let title: FilterType
var setting: String
}
However, the updated data is not being reflected on the table view.
I've tried assigning each data with an index path and updating the specific cell, but still doesn't reflect the change:
if let indexPath = filter.indexPath {
let foundIndexPath = IndexPath(row: indexPath.row, section: indexPath.section)
if let cell = tableView.cellForRow(at: foundIndexPath) {
cell.textLabel?.text = filter.setting
}
}
How I use the delegate method in the detail view controller:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedData = parsedData[indexPath.row]
// update the data to be passed
filter.setting = selectedData
// pass the data to the master view controller
delegate?.didSelectFilter(selectedFilter: filter)
self.navigationController?.popViewController(animated: true)
}
class Filter {
var title: FilterType!
var setting: String!
init(title: FilterType, setting: String) {
self.title = title
self.setting = setting
}
}
In other words, the Filter
object is created in the master view controller, passed to the detail view controller, gets modified, and then passed back to the master view controller. The problem is that the change doesn't get reflected in the master view controller's table view.
Upvotes: 0
Views: 559
Reputation: 77442
There are various ways to do this - and you can work on it using just your data first, then implement it in your multiple controllers.
Assuming you have something like this:
enum FilterType {
case TypeA, TypeB, TypeC, TypeD
}
struct Filter {
let title: FilterType
var setting: String
}
Here's an example you can run as a simple view controller:
class MasterViewController: UIViewController {
var filters: [Filter] = []
override func viewDidLoad() {
super.viewDidLoad()
// init array with 7 Filter objects, various "title" types
filters.append(Filter(title: .TypeA, setting: "1"))
filters.append(Filter(title: .TypeB, setting: "2"))
filters.append(Filter(title: .TypeC, setting: "3"))
filters.append(Filter(title: .TypeD, setting: "4"))
filters.append(Filter(title: .TypeB, setting: "5"))
filters.append(Filter(title: .TypeC, setting: "6"))
filters.append(Filter(title: .TypeB, setting: "7"))
print("array before update")
filters.forEach {
print($0)
}
print() // blank line
// create "selected" Filter - this would come from your Detail VC
let selFilter = Filter(title: .TypeB, setting: "Change Me")
didSelectFilter(selectedFilter: selFilter)
print("array after update")
filters.forEach {
print($0)
}
print() // blank line
}
func didSelectFilter(selectedFilter: Filter) {
// change .setting on each array element where .title == selectedFilter.title
filters.indices.filter { filters[$0].title == selectedFilter.title } .forEach {
filters[$0].setting = selectedFilter.setting
}
// tableView.reloadData()
}
}
The debug console output will look like this:
before
Filter(title: TestApp.FilterType.TypeA, setting: "1")
Filter(title: TestApp.FilterType.TypeB, setting: "2")
Filter(title: TestApp.FilterType.TypeC, setting: "3")
Filter(title: TestApp.FilterType.TypeD, setting: "4")
Filter(title: TestApp.FilterType.TypeB, setting: "5")
Filter(title: TestApp.FilterType.TypeC, setting: "6")
Filter(title: PanZoom.FilterType.TypeB, setting: "7")
after
Filter(title: TestApp.FilterType.TypeA, setting: "1")
Filter(title: TestApp.FilterType.TypeB, setting: "Change Me")
Filter(title: TestApp.FilterType.TypeC, setting: "3")
Filter(title: TestApp.FilterType.TypeD, setting: "4")
Filter(title: TestApp.FilterType.TypeB, setting: "Change Me")
Filter(title: TestApp.FilterType.TypeC, setting: "6")
Filter(title: PanZoom.FilterType.TypeB, setting: "Change Me")
As you can see, the elements where .title == .TypeB
had the .setting
property updated.
If your know your array will have only one element of each "title" type, instead of getting the indices of all elements with that type, you could do:
if let idx = filters.firstIndex(where: { $0.title == selectedFilter.title }) {
filters[idx].setting = selectedFilter.setting
}
Upvotes: 0
Reputation: 2982
Since your model is a struct
, i.e. value type, when creating the variable in for case var filter...
you are essentially creating a copy and not modifying the data source it self.
What you can do is either turn your model into a class so you are just creating a reference to the object in the data source or replace the object in the index path. For example:
for case var filter in filters where filter.title == selectedFilter.title {
filter.setting = selectedFilter.setting
self.filters[theRelevantIndexPosition] = filter
}
Upvotes: 1