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
相关产品推荐
相关产品推荐

