Open
Description
Description
I've encountered an odd situation where I am filtering some items from a data structure inside a snapshot.append()
items method call, and this appears to be causing the the append method to get called multiple times. Yet when I separate the filtering logic into a separate line, this issue appears to not be visible.
Reproduction
enum Section: String, CaseIterable {
case lifeEvents = "Life Events"
case physicalSensations = "Physical Sensations"
case mindThoughts = "Mind/Thoughts"
case bodyLocation = "Body Location"
}
func applySnapshot() {
var snapshot = NSDiffableDataSourceSnapshot<Section, EmotionExplorerViewController.FilterItem>()
snapshot.appendSections(Section.allCases)
for section in Section.allCases {
switch section {
case .lifeEvents:
snapshot.appendItems(filterItems.filter({$0.category == section}), toSection: section)
case .physicalSensations:
snapshot.appendItems(filterItems.filter({$0.category == section}), toSection: section)
case .mindThoughts:
snapshot.appendItems(filterItems.filter({$0.category == section}), toSection: section)
case .bodyLocation:
snapshot.appendItems(filterItems.filter({$0.category == section}), toSection: section)
}
}
emotionFiltersDataSource.apply(snapshot, animatingDifferences: true)
}
The following modification appears to not cause any problems:
func applySnapshot() {
var snapshot = NSDiffableDataSourceSnapshot<Section, EmotionExplorerViewController.FilterItem>()
snapshot.appendSections(Section.allCases)
for section in Section.allCases {
print("section cases,", Section.allCases)
print("section,", section)
if section == .lifeEvents {
let lifeEventItems = filterItems.filter({$0.category == .lifeEvents})
print("life event items count", lifeEventItems.count)
snapshot.appendItems(lifeEventItems, toSection: .lifeEvents)
} else if section == .physicalSensations {
let physicalSensationsItems = filterItems.filter({$0.category == .physicalSensations})
print("physical sensations items count", physicalSensationsItems.count)
snapshot.appendItems(physicalSensationsItems, toSection: .physicalSensations)
} else if section == .mindThoughts {
let mindThoughtsItems = filterItems.filter({$0.category == .mindThoughts})
print("mind thoughts items count", mindThoughtsItems.count)
snapshot.appendItems(mindThoughtsItems, toSection: .mindThoughts)
} else if section == .bodyLocation {
let bodyLocationItems = filterItems.filter({$0.category == .bodyLocation})
print("body location items count", bodyLocationItems.count)
snapshot.appendItems(bodyLocationItems, toSection: .bodyLocation)
}
}
emotionFiltersDataSource.apply(snapshot, animatingDifferences: true)
}
This is the rest of the code on how I am constructing my data structure:
var filterItems: [EmotionExplorerViewController.FilterItem] = []
func setupInitialData() {
let physicalSensationsFilterNames = ["Tired/Fatigued", "Energetic/Alert", "Calm/Relaxed", "Restless/Fidgety", "Heavy/Weighted Down", "Light/Buzzing", "Tense/Tight", "Numb/Tingling"]
let lifeFilterNames = ["Work", "Family/Relationships", "Social", "Health/Physical Wellbeing"]
let bodyLocationFilterNames = ["Head", "Neck/Throat", "Chest/Heart", "Shoulders", "Arms/Hands", "Solar Plexus", "Stomach/Gut", "Lower Abdomen/Core", "Legs/Feet", "Whole Body"]
let mindThoughtsFilterNames = ["Racing/Fast", "Focused/Clear", "Confused/Foggy", "Overthinking/Spiralling", "Blank", "Reflective/Meditative"]
do {
try filterItems.append(contentsOf: bodyLocationFilterNames.map { name in
if name == "Head" {
return EmotionExplorerViewController.FilterItem.head(isSelected: false)
} else if name == "Neck/Throat" {
return EmotionExplorerViewController.FilterItem.neck(isSelected: false)
} else if name == "Chest/Heart" {
return EmotionExplorerViewController.FilterItem.chest(isSelected: false)
} else if name == "Shoulders" {
return EmotionExplorerViewController.FilterItem.shoulders(isSelected: false)
} else if name == "Arms/Hands" {
return EmotionExplorerViewController.FilterItem.arms(isSelected: false)
} else if name == "Solar Plexus" {
return EmotionExplorerViewController.FilterItem.solarPlexus(isSelected: false)
} else if name == "Stomach/Gut" {
return EmotionExplorerViewController.FilterItem.stomach(isSelected: false)
} else if name == "Lower Abdomen/Core" {
return EmotionExplorerViewController.FilterItem.lowerAbdomen(isSelected: false)
} else if name == "Legs/Feet" {
return EmotionExplorerViewController.FilterItem.legs(isSelected: false)
} else if name == "Whole Body" {
return EmotionExplorerViewController.FilterItem.wholeBody(isSelected: false)
} else {
throw MapFilterError.filterNotFound("filter name not found in body location category.")
}
})
} catch let error {
print("map filters in body location category error,", error)
}
do {
try filterItems.append(contentsOf: physicalSensationsFilterNames.map { name in
if name == "Tired/Fatigued" {
return EmotionExplorerViewController.FilterItem.tired(isSelected: false)
} else if name == "Energetic/Alert" {
return EmotionExplorerViewController.FilterItem.energetic(isSelected: false)
} else if name == "Calm/Relaxed" {
return EmotionExplorerViewController.FilterItem.calm(isSelected: false)
} else if name == "Restless/Fidgety" {
return EmotionExplorerViewController.FilterItem.restless(isSelected: false)
} else if name == "Heavy/Weighted Down" {
return EmotionExplorerViewController.FilterItem.heavy(isSelected: false)
} else if name == "Light/Buzzing" {
return EmotionExplorerViewController.FilterItem.light(isSelected: false)
} else if name == "Tense/Tight" {
return EmotionExplorerViewController.FilterItem.tense(isSelected: false)
} else if name == "Numb/Tingling" {
return EmotionExplorerViewController.FilterItem.numb(isSelected: false)
} else {
throw MapFilterError.filterNotFound("filter name not found in physical sensations category.")
}
})
} catch let error {
print("map filters in physical sensations category error,", error)
}
do {
try filterItems.append(contentsOf: lifeFilterNames.map { name in
switch name {
case "Work":
return EmotionExplorerViewController.FilterItem.work(isSelected: false)
case "Family/Relationships":
return EmotionExplorerViewController.FilterItem.family(isSelected: false)
case "Social":
return EmotionExplorerViewController.FilterItem.social(isSelected: false)
case "Health/Physical Wellbeing":
return EmotionExplorerViewController.FilterItem.health(isSelected: false)
default:
throw MapFilterError.filterNotFound("filter name not found in life filter names category")
}
})
} catch let error {
print("map filters in life filter names category error,", error)
}
do {
try filterItems.append(contentsOf: mindThoughtsFilterNames.map { name in
switch name {
case "Racing/Fast":
return EmotionExplorerViewController.FilterItem.racing(isSelected: false)
case "Focused/Clear":
return EmotionExplorerViewController.FilterItem.focused(isSelected: false)
case "Confused/Foggy":
return EmotionExplorerViewController.FilterItem.confused(isSelected: false)
case "Overthinking/Spiralling":
return EmotionExplorerViewController.FilterItem.overthinking(isSelected: false)
case "Blank":
return EmotionExplorerViewController.FilterItem.blank(isSelected: false)
case "Reflective/Meditative":
return EmotionExplorerViewController.FilterItem.reflective(isSelected: false)
default:
throw MapFilterError.filterNotFound("filter name not found in mind thoughts filter names category")
}
})
} catch let error {
print("map filters in mind thought filters category error,", error)
}
}
enum FilterItem: Hashable {
case work(isSelected: Bool)
case family(isSelected: Bool)
case health(isSelected: Bool)
case social(isSelected: Bool)
case energetic(isSelected: Bool)
case tired(isSelected: Bool)
case restless(isSelected: Bool)
case heavy(isSelected: Bool)
case numb(isSelected: Bool)
case calm(isSelected: Bool)
case tense(isSelected: Bool)
case light(isSelected: Bool)
case racing(isSelected: Bool)
case focused(isSelected: Bool)
case confused(isSelected: Bool)
case overthinking(isSelected: Bool)
case blank(isSelected: Bool)
case reflective(isSelected: Bool)
case head(isSelected: Bool)
case neck(isSelected: Bool)
case chest(isSelected: Bool)
case shoulders(isSelected: Bool)
case arms(isSelected: Bool)
case solarPlexus(isSelected: Bool)
case stomach(isSelected: Bool)
case lowerAbdomen(isSelected: Bool)
case legs(isSelected: Bool)
case wholeBody(isSelected: Bool)
var filterName: String {
switch self {
case .work: return "Work"
case .family: return "Family/Relationships"
case .health: return "Health/Physical Wellbeing"
case .social: return "Social"
case .energetic: return "Energetic/Alert"
case .tired: return "Tired/Fatigued"
case .restless: return "Restless/Fidgety"
case .heavy: return "Heavy/Weighted Down"
case .numb: return "Numb/Tingling"
case .calm: return "Calm/Relaxed"
case .tense: return "Tense/Tight"
case .light: return "Light/Buzzing"
case .racing: return "Racing/Fast"
case .focused: return "Focused/Clear"
case .confused: return "Confused/Foggy"
case .overthinking: return "Overthinking/Spiralling"
case .blank: return "Blank"
case .reflective: return "Reflective/Meditative"
case .head: return "Head"
case .neck: return "Neck/Throat"
case .chest: return "Chest/Heart"
case .shoulders: return "Shoulders"
case .arms: return "Arms/Hands"
case .solarPlexus: return "Solar Plexus"
case .stomach: return "Stomach/Gut"
case .lowerAbdomen: return "Lower Abdomen/Core"
case .legs: return "Legs/Feet"
case .wholeBody: return "Whole Body"
}
}
var category: EmotionFiltersViewController.Section {
switch self {
case .work: return .lifeEvents
case .family: return .lifeEvents
case .health: return .lifeEvents
case .social: return .lifeEvents
case .energetic: return .physicalSensations
case .tired: return .physicalSensations
case .restless: return .physicalSensations
case .heavy: return .physicalSensations
case .calm: return .physicalSensations
case .tense: return .physicalSensations
case .light: return .physicalSensations
case .numb: return .physicalSensations
case .racing: return .mindThoughts
case .focused: return .mindThoughts
case .confused: return .mindThoughts
case .overthinking: return .mindThoughts
case .blank: return .mindThoughts
case .reflective: return .mindThoughts
case .head: return .bodyLocation
case .neck: return .bodyLocation
case .chest: return .bodyLocation
case .shoulders: return .bodyLocation
case .arms: return .bodyLocation
case .solarPlexus: return .bodyLocation
case .stomach: return .bodyLocation
case .lowerAbdomen: return .bodyLocation
case .legs: return .bodyLocation
case .wholeBody: return .bodyLocation
}
}
var isSelected: Bool {
switch self {
case .work(let isSelected): return isSelected
case .family(let isSelected): return isSelected
case .health(let isSelected): return isSelected
case .social(let isSelected): return isSelected
case .energetic(let isSelected):
return isSelected
case .tired(let isSelected):
return isSelected
case .restless(let isSelected):
return isSelected
case .heavy(let isSelected):
return isSelected
case .calm(let isSelected):
return isSelected
case .tense(let isSelected):
return isSelected
case .light(let isSelected):
return isSelected
case .numb(let isSelected):
return isSelected
case .racing(let isSelected):
return isSelected
case .focused(let isSelected):
return isSelected
case .confused(let isSelected):
return isSelected
case .overthinking(let isSelected):
return isSelected
case .blank(let isSelected):
return isSelected
case .reflective(let isSelected):
return isSelected
case .head(let isSelected):
return isSelected
case .neck(let isSelected):
return isSelected
case .chest(let isSelected):
return isSelected
case .shoulders(let isSelected):
return isSelected
case .arms(let isSelected):
return isSelected
case .solarPlexus(let isSelected):
return isSelected
case .stomach(let isSelected):
return isSelected
case .lowerAbdomen(let isSelected):
return isSelected
case .legs(let isSelected): return isSelected
case .wholeBody(let isSelected): return isSelected
}
}
}
Expected behavior
I expect each of the statements in the switch statement to execute exactly once, however they are executing multiple times.
Environment
swift version 5.0
Additional information
No response