You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift:使用Calendar.component致App无报错冻结的解决方案

问题描述

背景

我有一个自定义Day结构体,内部使用Swift Date属性。我希望该结构体能够判断另一个给定的Day是否与自身为同一星期几。但每次执行相关代码时,我的App会冻结且无任何运行时错误。

代码

struct Day: Hashable {
    private let calendar: Calendar = .current
    let date: Date

    static func == (lhs: Day, rhs: Day) -> Bool {
        return Calendar.current.isDate(lhs.date, inSameDayAs: rhs.date)
    }

    func isSameDayOfTheWeek(as day: Day) -> Bool {
        // Replacing this Line to RETURN TRUE prevents the Crash.
        return calendar.component(.weekday, from: self.date) == calendar.component(.weekday, from: day.date)
    }
}

enum Time: Int16, Comparable, Identifiable, CaseIterable {
    case morning, noon, evening, night
    
    var id: Int16 { self.rawValue }
    var name: String { ... }
}

struct ToDo: Hashable, Identifiable {
    let id: UUID = UUID()
    let block: Block // NSManagedObject
    let day: Day
    let time: Time
}

struct ToDoView: View {
    @FetchRequest(sortDescriptors: [SortDescriptor(\.creationTS)]) private var blocks: FetchedResults<Block>

    var body: some View {
        ForEach(toDos) { toDo in
            Text(toDo.name)
        }
    }

    private var toDos: [ToDo] {
        var toDos: [ToDo] = []

        for block in blocks {
            let startDay: Day = block.safeStartDay

            var day: Day = .today
            while day >= startDay {
                // Removing this Line prevents the Crash.
                guard startDay.isSameDayOfTheWeek(as: day) else { continue }

                for time in Time.allCases {
                    toDos.append(ToDo(block: block, day: day, time: time))
                }

                day = day - 1
            }
        }

        return toDos
    }
}

问题

如何解决该冻结问题,同时仍能判断另一个给定的Day是否与当前Day结构体实例为同一星期几?


解决方案

问题根源

App冻结是因为无限循环:在while day >= startDay循环中,当startDay.isSameDayOfTheWeek(as: day)条件不成立时,continue会跳过后续的day = day - 1代码,导致day的值始终不变,循环条件永远满足,无法退出。

修复步骤

1. 调整循环逻辑,避免无限循环

修改toDos计算属性的循环部分,确保无论是否匹配星期几的条件,都执行日期递减操作:

private var toDos: [ToDo] {
    var toDos: [ToDo] = []

    for block in blocks {
        let startDay: Day = block.safeStartDay

        var day: Day = .today
        while day >= startDay {
            if startDay.isSameDayOfTheWeek(as: day) {
                for time in Time.allCases {
                    toDos.append(ToDo(block: block, day: day, time: time))
                }
            }
            // 无论条件是否满足,都必须递减日期,确保循环能正常退出
            day = day - 1
        }
    }

    return toDos
}

2. 完善Day结构体的必要实现

确保Day结构体正确实现Comparable协议和减法操作符,保证day >= startDay和day = day -1的行为符合预期:

extension Day: Comparable {
    static func < (lhs: Day, rhs: Day) -> Bool {
        return lhs.date < rhs.date
    }

    static func - (lhs: Day, days: Int) -> Day {
        guard let newDate = lhs.calendar.date(byAdding: .day, value: -days, to: lhs.date) else {
            return lhs // 处理日期计算失败的边界情况
        }
        return Day(date: newDate)
    }

    // 支持`day - 1`的简洁语法
    static func - (lhs: Day, rhs: Int) -> Day {
        return lhs - rhs
    }
}

// 补充.today静态属性的实现(如果未定义)
extension Day {
    static var today: Day {
        Day(date: Date())
    }
}

内容的提问来源于stack exchange,提问作者christophriepe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 16:00:26