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

iOS用UserDefaults与Core Data实现连续天数计数器遇类型转换报错

问题修复方案

错误原因

  • Swift 3+版本已废弃Objective-C风格的NSDate、NSCalendar系列API,原生Date、Calendar类型不会和旧类型隐式转换,枚举值NSCalendar.Unit也重构为Calendar.Component类型,是报错的直接原因
  • 原有逻辑中调用changeDateTime后未接收返回值,调整后的日期没有生效,连续天数统计逻辑会失效

修正后完整代码

import UIKit
import CoreData

let userDefaults = UserDefaults.standard
var moc: NSManagedObjectContext!

var lastStreakEndDate: Date!
var streakTotal: Int!

override func viewDidLoad() {
    super.viewDidLoad()

    // 首次运行初始化存储
    if userDefaults.object(forKey: "lastStreakEndDate") == nil {
        userDefaults.set(Date(), forKey: "lastStreakEndDate")
    }
    lastStreakEndDate = userDefaults.object(forKey: "lastStreakEndDate") as! Date
    streakTotal = calculateStreak(lastDate: lastStreakEndDate)
}

// 读取上次统计节点之前的所有打卡日期
func fetchLatestDates(moc: NSManagedObjectContext, lastDate: Date) -> [Date] {
    var dates = [Date]()
    // 替换为你的Core Data实体类名,注意首字母大写
    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "StreakCount")
    let datePredicate = NSPredicate(format: "date < %@", lastDate as NSDate)
    fetchRequest.predicate = datePredicate

    do {
        let result = try moc.fetch(fetchRequest)
        // 若Core Data属性存储为NSDate类型,此处对应转换即可
        let allDates = result as! [Date]
        if !allDates.isEmpty {
            dates.append(contentsOf: allDates)
        }
    } catch {
        fatalError("读取打卡记录失败: \(error)")
    }
    return dates
}

// 将日期调整为当日23:59:59
func changeDateTime(userDate: Date) -> Date {
    var dateComponents = Calendar.current.dateComponents([.year, .month, .day], from: userDate)
    dateComponents.hour = 23
    dateComponents.minute = 59
    dateComponents.second = 59
    return Calendar.current.date(from: dateComponents) ?? userDate
}

// 日期加1天
func addDay(today: Date) -> Date {
    return Calendar.current.date(byAdding: .day, value: 1, to: today) ?? today
}

// 计算连续打卡天数
func calculateStreak(lastDate: Date) -> Int {
    let dateList = fetchLatestDates(moc: moc, lastDate: lastDate)
    let compareDate = changeDateTime(userDate: lastDate)
    var streakDateList = [Date]()
    var tomorrow = addDay(today: compareDate)

    for date in dateList {
        // 修复原逻辑未接收调整后日期的问题
        let adjustedDate = changeDateTime(userDate: date)
        if adjustedDate == tomorrow {
           streakDateList.append(date)
           tomorrow = addDay(today: adjustedDate)
        } else {
            // 连续中断直接跳出循环
            break
        }
    }

    userDefaults.set(streakDateList.last ?? lastDate, forKey: "lastStreakEndDate")
    return streakDateList.count
}

额外说明

如果你的Core Data实体中date属性定义为NSDate类型,只需要在需要转换的位置加as Date/as NSDate显式转换即可。

内容的提问来源于stack exchange,提问作者Rem Biths Wind

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 11:39:04