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

UICalendarView选择未来108天以后日期时崩溃问题求助

问题:UICalendarView添加装饰时,未来超过108天的日期导致崩溃

我正在开发一款预测未来特定日期的App,在为UICalendarView添加装饰时遇到问题。当选择未来超过108天的日期,或为该类日期添加日历装饰时,App会崩溃。

报错日志

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Attempted to reconfigure item identifier that does not exist in the snapshot: <_UIDatePickerCalendarDay: 0x600000ca8b40; components: 1-2024-2-14; month: <_UIDatePickerCalendarMonth: 0x600000ca8d50; calendar: <_NSSwiftCalendar: 0x60000000d640>; components: 1-2024-2>; assignedMonth: (null)>'
*** First throw call stack:
(
    0   CoreFoundation                      0x00000001804658a8 __exceptionPreprocess + 172
    1   libobjc.A.dylib                     0x000000018005c09c objc_exception_throw + 56
    2   Foundation                          0x0000000180cf3a5c _userInfoForFileAndLine + 0
    3   UIKitCore                           0x00000001046abe40 -[__UIDiffableDataSourceSnapshot _validateReloadUpdateThrowingIfNeeded:] + 436
    4   UIKitCore                           0x00000001046abad4 -[__UIDiffableDataSourceSnapshot _commitUpdateAtomic:] + 100
    5   UIKitCore                           0x00000001046ab0a8 -[__UIDiffableDataSourceSnapshot reconfigureItemsWithIdentifiers:] + 76
    6   UIKitCore                           0x00000001046db21c -[UICalendarView reloadDecorationsForDateComponents:animated:] + 132
    7   DJTimeOff                           0x0000000102f18d74 $s9DJTimeOff14DJCalendarViewV12updateUIView_7contextySo010UICalendarD0C_7SwiftUI0F20RepresentableContextVyACGtF + 1208
    8   DJTimeOff                           0x0000000102f1b430 $s9DJTimeOff14DJCalendarViewV7SwiftUI19UIViewRepresentableAadEP06updateG0_7contexty0G4TypeQz_AD0gH7ContextVyxGtFTW + 12
    9   SwiftUI                             0x000000010a19a5ac OUTLINED_FUNCTION_9 + 163208
    10  SwiftUI                             0x000000010a0e611c OUTLINED_FUNCTION_71 + 16892
    11  SwiftUI                             0x000000010a0e603c OUTLINED_FUNCTION_71 + 16668
    12  SwiftUI                             0x000000010a0c6b68 OUTLINED_FUNCTION_11 + 63844
    13  SwiftUI                             0x000000010a0e5ed4 OUTLINED_FUNCTION_71 + 16308
    14  SwiftUI                             0x000000010a0e5cec OUTLINED_FUNCTION_71 + 15820
    15  SwiftUI                             0x000000010a0e4f78 OUTLINED_FUNCTION_71 + 12376
    16  SwiftUI                             0x0000000109c6e1c0 __swift_allocate_boxed_opaque_existential_1Tm + 208
    17  AttributeGraph                      0x000000019e9fa750 _ZN2AG5Graph11UpdateStack6updateEv + 504
    18  AttributeGraph                      0x000000019e9faee0 _ZN2AG5Graph16update_attributeENS_4data3ptrINS_4NodeEEEj + 432
    19  AttributeGraph                      0x000000019ea088d0 _ZN2AG8Subgraph6updateEj + 828
    20  SwiftUI                             0x0000000109ff7418 OUTLINED_FUNCTION_0 + 10148
    21  SwiftUI                             0x000000010a0c45a4 OUTLINED_FUNCTION_11 + 54176
    22  SwiftUI                             0x000000010a0beec0 OUTLINED_FUNCTION_11 + 31932
    23  SwiftUI                             0x000000010a377578 OUTLINED_FUNCTION_39 + 34700
    24  SwiftUI                             0x000000010a3775bc OUTLINED_FUNCTION_39 + 34768
    25  UIKitCore                           0x000000010512ab1c -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1492
    26  QuartzCore                          0x00000001884d3dd4 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 440
    27  QuartzCore                          0x00000001884deb30 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 124
    28  QuartzCore                          0x00000001883fa3bc _ZN2CA7Context18commit_transactionEPNS_11TransactionEdPd + 460
    29  QuartzCore                          0x0000000188429bf0 _ZN2CA11Transaction6commitEv + 652
    30  UIKitCore                           0x0000000104c30504 __34-[UIApplication _firstCommitBlock]_block_invoke_2 + 32
    31  CoreFoundation                      0x00000001803c6464 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 20
    32  CoreFoundation                      0x00000001803c5bac __CFRunLoopDoBlocks + 352
    33  CoreFoundation                      0x00000001803c0450 __CFRunLoopRun + 788
    34  CoreFoundation                      0x00000001803bfd28 CFRunLoopRunSpecific + 572
    35  GraphicsServices                    0x000000018986ebc0 GSEventRunModal + 160
    36  UIKitCore                           0x0000000104c17fdc -[UIApplication _run] + 868
    37  UIKitCore                           0x0000000104c1bc54 UIApplicationMain + 124
    38  SwiftUI                             0x0000000109af8524 OUTLINED_FUNCTION_70 + 500
    39  SwiftUI                             0x0000000109af83c4 OUTLINED_FUNCTION_70 + 148
    40  SwiftUI                             0x000000010980a108 OUTLINED_FUNCTION_2 + 92
    41  DJTimeOff                           0x0000000102f15db4 $s9DJTimeOff0aB3AppV5$mainyyFZ + 40
    42  DJTimeOff                           0x0000000102f16340 main + 12
    43  dyld                                0x00000001030f9558 start_sim + 20
    44  ???                                 0x00000001032f9f28 0x0 + 4348419880
    45  ???                                 0xaf6e800000000000 0x0 + 12641181941563916288
)
libc++abi: terminating due to uncaught exception of type NSException

相关代码

设置日期的方法

func setDaysOff(startDate:Date, numberOfDays:Int) {
    self.changedDayOff = nil
    daysOff.removeAll()
    let newday = DayOff(firstDay: startDate, dayIcon: .firstDay)
    let newday2 = DayOff(firstDay: startDate.diff(numDays: 1), dayIcon: .secondDay)
    let newday3 = DayOff(firstDay: startDate.diff(numDays: 2), dayIcon: .thirdDay)
    daysOff.append(newday)
    daysOff.append(newday2)
    daysOff.append(newday3)
    for dy in 1...numberOfDays - 1  {
        let newDay = DayOff(firstDay: startDate.diff(numDays: 9 * dy),dayIcon: .firstDay)
        let newday2 = DayOff(firstDay: startDate.diff(numDays: (9 * dy) + 1), dayIcon: .secondDay)
        let newday3 = DayOff(firstDay: startDate.diff(numDays: (9 * dy) + 2), dayIcon: .thirdDay)
        daysOff.append(newDay)
        daysOff.append(newday2)
        daysOff.append(newday3)
    }
    changedDayOff = newday
}

更新日历装饰的方法

func updateUIView(_ uiView: UICalendarView, context: Context) {
    if DS.changedDayOff != nil {
            for te in 0..<DS.daysOff.count {
                uiView.reloadDecorations(forDateComponents: [DS.daysOff[te].dateComponents], animated: true)
            }
    }
}

解决方案

问题原因

UICalendarView默认的availableDateRange范围有限(通常是当前日期前后各54天,总共108天左右),当尝试为超出这个范围的日期调用reloadDecorations时,这些日期不在日历当前的数据源快照中,就会触发NSInternalInconsistencyException崩溃。

解决办法

1. 过滤超出可用范围的日期

在调用reloadDecorations前,先过滤掉不在UICalendarView可用范围内的日期组件:

func updateUIView(_ uiView: UICalendarView, context: Context) {
    guard DS.changedDayOff != nil else { return }
    
    // 获取日历的可用日期范围,默认用当前日期前后1年作为 fallback
    let availableRange = uiView.availableDateRange ?? DateInterval(
        start: Date(), 
        end: Date().addingTimeInterval(60*60*24*365)
    )
    
    // 过滤出有效日期组件
    let validComponents = DS.daysOff.compactMap { dayOff in
        guard let date = Calendar.current.date(from: dayOff.dateComponents),
              availableRange.contains(date) else {
            return nil
        }
        return dayOff.dateComponents
    }
    
    if !validComponents.isEmpty {
        uiView.reloadDecorations(forDateComponents: validComponents, animated: true)
    }
}

2. 扩大UICalendarView的可用日期范围

在初始化UICalendarView时,设置覆盖所有需要添加装饰的日期范围:

func makeUIView(context: Context) -> UICalendarView {
    let calendarView = UICalendarView()
    
    // 设置覆盖未来1年的可用范围,可根据实际需求调整
    let startDate = Date()
    let endDate = startDate.addingTimeInterval(60*60*24*365)
    calendarView.availableDateRange = DateInterval(start: startDate, end: endDate)
    
    // 其他日历配置(如选择样式、装饰代理等)
    return calendarView
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 22:37:01