CollectionView Cell 會重用(dequeueReusableCellWithReuseIdentifier),滑動換月份時 Cell 被回收重用,若選中狀態只存在 Cell 實例上(如 cell.isSelected),離開畫面後狀態即丟失。
原則:選中狀態屬於資料模型,不屬於 Cell 視圖。
struct DayModel {
let date: Date
var isSelected: Bool
// 其他:isCurrentMonth, isToday, eventCount 等
}
var monthData: [Date: [DayModel]] = [:] // key: 月份首日 Date
func collectionView(_ cv: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = cv.dequeueReusableCell(withReuseIdentifier: "DayCell", for: indexPath) as! DayCell
let day = monthData[currentMonth]![indexPath.item]
cell.configure(with: day) // 內部設定 day.isSelected ? 高亮 : 正常
return cell
}
func collectionView(_ cv: UICollectionView, didSelectItemAt indexPath: IndexPath) {
var day = monthData[currentMonth]![indexPath.item]
day.isSelected.toggle()
monthData[currentMonth]![indexPath.item] = day
cv.reloadItems(at: [indexPath]) // 或 cv.performBatchUpdates
}
func switchToMonth(_ monthStart: Date) {
currentMonth = monthStart
if monthData[monthStart] == nil {
monthData[monthStart] = generateDaysForMonth(monthStart)
}
collectionView.reloadData()
}
var selectedDates: Set<Date> = [],Cell 配置時 day.isSelected = selectedDates.contains(day.date)。selectedDates 序列化存入 UserDefaults / CoreData / Realm,啟動時還原。UICollectionViewCompositionalLayout + Diffable Data Source (iOS 13+),局部更新更高效。var isSelected = false)。reloadData() 會重建所有可見 Cell,配合模型正確無誤;若卡頓改用 reloadItems(at:)。