gpt4 book ai didi

ios - 在获取核心数据之后但在显示 TableView 之前,如何更新依赖于当前时间的字段?

转载 作者:行者123 更新时间:2023-11-29 05:54:14 25 4
gpt4 key购买 nike

问题总结

我正在编写一个iOS应用程序,就像待办事项列表和日历之间的混合体。与待办事项列表不同,您不需要将所有内容都检查完整。而是将待办事项放置在UITableView中用于活动和非活动的部分中。问题是该节和排序可能相对于当前日期和时间在任何时间发生变化。

因此,当前在获取数据之后但视图控制器开始显示它之前,在初始应用程序加载时如何以及何时刷新section / nextAlert日期,目前我一直在苦苦挣扎。

我尝试过的背景

我已经研究并尝试了许多不同的方法来解决这些问题。


提取后在viewDidLoad中刷新。我试图在viewDidLoad期间在表视图控制器中获取数据后立即调用refreshReminders函数。只要我实际上没有在该函数中保存到核心数据,这似乎就可以正常工作。只需在一个或多个记录上设置字段即可触发控制器,并且行将按其应有的方式移动和更新。尽管看起来加载顺序可能为时已晚。我们是否真的希望表视图在应用程序首次启动时必须正确地移动记录?这听起来像是不好的做法。


现在,如果我尝试在刷新后将更改保存到核心数据,那么它就变得很奇怪。该表显然是根据当前上下文中记录的更改来更新的,但是当上下文被保存时,它将再次触发更改!由于已经进行了更改,因此在尝试将行从旧位置移动到新位置后,该应用程序崩溃。请参见下面的代码。


在获取唤醒之前刷新。我还尝试使用对核心数据对象的扩展(提醒)来设置节和nextAlert日期。但是,这似乎没有任何作用。即,该表仍然以错误的部分和/或排序顺序加载了提醒。


刷新此处的字段也不会将数据标记为“脏”(已更改),因此表视图控制器不会移动它,并且仅当数据为脏时才触发的上下文保存当然不会触发。我什至尝试在获取后保存上下文,而无需检查其是否已更改,但这也不起作用。也就是说,即使核心数据确实没有任何变化,它也确实没有任何变化。

这是代码

这是我的tableViewController的控制器函数中的.move情况

case .move:
if let oldPath = indexPath, let newPath = newIndexPath {
os_log("RemindersViewController: Move was triggered, now updating row in table. Old path was %{public}@ and new path is %{public}@", log: OSLog.default, type: .info, oldPath as CVarArg, newPath as CVarArg)
RemindersCell, withReminder: anObject as! Reminders)
configureCell(tableView.cellForRow(at: oldPath) as! RemindersCell, withReminder: anObject as! Reminders)
os_log("RemindersViewController: updated moved cell.", log: OSLog.default, type: .info)


// Don't actually try to move it if the old and new path are the same
if (newPath != oldPath) {
os_log("RemindersViewController: Moving row in table.", log: OSLog.default, type: .info)
tableView.moveRow(at: oldPath, to: newPath)
os_log("RemindersViewController: row moved.", log: OSLog.default, type: .info)
}
}


这是我的configureCell函数的简化版本。

    func configureCell(_ cell: RemindersCell, withReminder reminder: Reminders) {
cell.labelTitleField!.text = reminder.title ?? "New Reminder"
cell.labelAlertField!.text = reminder.nextAlert!.description
}


我正在使用beginUpdates()和endUpdates()批处理更新,以便如果一次有大量更改,则OS可以找出同时处理所有变化和动画化所有动作的最佳方法。

// Batch the updates to the table. Start with beginUpdates so all the action animations are queued up.
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}


// Batch the updates to the table. End with endUpdates to trigger the actual animations.
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.endUpdates()
}


这是控制台中与该代码相关的内容:

2019-03-23 12:31:09.307801-0500 Scheduler[5711:2218287] RemindersViewContoller in viewDidLoad: Fetched records successfully.
Refreshing reminders!
2019-03-23 12:31:09.311755-0500 Scheduler[5711:2218287] Reminder 'Test Non-recurring Reminder' section updated to Inactive.
2019-03-23 12:31:09.313254-0500 Scheduler[5711:2218287] RemindersViewController: Move was triggered, now updating row in table. Old path was <NSIndexPath: 0x28078e480> {length = 2, path = 0 - 0} and new path is <NSIndexPath: 0x28078f140> {length = 2, path = 1 - 2}
Scheduler was compiled with optimization - stepping may behave oddly; variables may not be available.
(lldb)


因此,似乎操作系统本身已在某种程度上不使用我的控制器功能而将提醒移到了它所属的位置。刷新各个提醒字段时必须执行此操作,但是当我将上下文保存到核心数据时,它将再次调用我的控制器函数来执行已经完成的移动。

预期和实际结果

我想我已经在上面进行了介绍,但总而言之,我想知道在表视图显示数据之前更改获取的数据的最佳方法是,使所有数据都位于相对于当前日期和时间的正确部分和排序顺序中。

更新

只要注释掉保存到核心数据,这就是refreshReminder例程就可以完美地工作。在执行提醒记录的初始获取后,立即调用此函数:

// Handle updating nextAlert and section based on current date and time
func refreshReminders () {

// Loop through the records and update the time-sensitive section and nextAlert fields
print("Refreshing reminders!")
for reminder in fetchedController.fetchedObjects! {
if (reminder.nextAlert! < Date()) {
if (reminder.recurrence != "Never") {
let nextAlert = nextAlertDate(alertDate: reminder.alert!, recurrencePattern: reminder.recurrence)
if (reminder.nextAlert != nextAlert) {
reminder.nextAlert = nextAlert
os_log("Reminder '%{public}@' nextAlert date updated to %{public}@.", reminder.title!, String(describing: reminder.nextAlert!))
}
}
let section = getSection(nextAlertDate: reminder.nextAlert!)
if (reminder.section != section) {
reminder.section = section
//print("Reminder section updated to", reminder.section!)
os_log("Reminder '%{public}@' section updated to %{public}@.", reminder.title!, reminder.section!)
}
}
} //endfor

// Save changes to core data if there are any
/*if context.hasChanges {
do {
try context.save()
print("RemindersViewController in refreshReminders: Changes to core data, so saving them now.")
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
} //enddo
}*/ //endif

} //endfunc refreshReminders


这是在初次启动应用程序时将提醒从一个部分更新/移动到另一部分的结果,因为提醒时间已经过去:

2019-03-23 18:26:24.796406-0500 Scheduler[6383:2371662] AppDelegate: Initialized core data stack
2019-03-23 18:26:24.801211-0500 Scheduler[6383:2371734] AppDelegate: Notification authorization granted.
2019-03-23 18:26:24.806165-0500 Scheduler[6383:2371734] AppDelegate: Set our custom notification categories and actions.
2019-03-23 18:26:24.810726-0500 Scheduler[6383:2371662] RemindersViewContoller in viewDidLoad: Fetched records successfully.
Refreshing reminders!
2019-03-23 18:26:24.814331-0500 Scheduler[6383:2371662] Reminder 'Test Non-recurring Reminder' section updated to Inactive.
Number of sections: 2
2019-03-23 18:26:24.815463-0500 Scheduler[6383:2371662] RemindersViewController in viewWillAppear: We're here. Let's see how often we get triggered!
Number of sections: 2
Number of records in section 1 : 3
Number of records in section 0 : 7
Number of sections: 2
Number of records in section 1 : 3
Number of records in section 0 : 7
2019-03-23 18:26:24.893329-0500 Scheduler[6383:2371662] RemindersViewController: Move was triggered, now updating row in table. Old path was <NSIndexPath: 0x28047a900> {length = 2, path = 0 - 0} and new path is <NSIndexPath: 0x28047a920> {length = 2, path = 1 - 3}
2019-03-23 18:26:24.893498-0500 Scheduler[6383:2371662] RemindersViewController: updated moved cell.
2019-03-23 18:26:24.893511-0500 Scheduler[6383:2371662] RemindersViewController: Moving row in table.
2019-03-23 18:26:24.893524-0500 Scheduler[6383:2371662] RemindersViewController: row moved.
Number of sections: 2
Number of sections: 2
Number of records in section 0 : 6
Number of records in section 1 : 4


当我取消注释保存到核心数据时,这是os_log和错误。它在configCell上崩溃。

2019-03-23 18:35:22.210467-0500 Scheduler[6396:2375020] AppDelegate: Initialized core data stack
2019-03-23 18:35:22.215964-0500 Scheduler[6396:2375092] AppDelegate: Notification authorization granted.
2019-03-23 18:35:22.220937-0500 Scheduler[6396:2375092] AppDelegate: Set our custom notification categories and actions.
2019-03-23 18:35:22.227273-0500 Scheduler[6396:2375020] RemindersViewContoller in viewDidLoad: Fetched records successfully.
Refreshing reminders!
2019-03-23 18:35:22.230832-0500 Scheduler[6396:2375020] Reminder 'Test Non-recurring Reminder' section updated to Inactive.
2019-03-23 18:35:22.232326-0500 Scheduler[6396:2375020] RemindersViewController: Move was triggered, now updating row in table. Old path was <NSIndexPath: 0x282e6d360> {length = 2, path = 0 - 0} and new path is <NSIndexPath: 0x282e6df60> {length = 2, path = 1 - 3}
Scheduler was compiled with optimization - stepping may behave oddly; variables may not be available.
(lldb)


configureCell(tableView.cellForRow(at: oldPath) as! RemindersCell, withReminder: anObject as! Reminders)
Thread 1: EXC_BREAKPOINT (code=1, subcode=0x104048220)

最佳答案

事实证明,即使单元格本身为零,也可以发送移动行请求。 PaulW11指出,这很可能是因为该单元实际上尚未在屏幕上可见。因此,处理此问题的方法是,当且仅当它不是nil时才更新(配置)单元格,但是只要我们有一个有效的oldPath和newPath,就继续处理该行的移动。我更新的效果很好的代码是:

case .move:
// If we have an old and new path, proceed with moving and/or updating the cell
if let oldPath = indexPath, let newPath = newIndexPath {

if let cell = tableView.cellForRow(at: oldPath) as? RemindersCell, let reminder = anObject as? Reminders {
os_log("RemindersViewController: Move was triggered, so updating cell in table. Reminder is: %{public}@", log: .default, type: .info, reminder)
configureCell(cell, withReminder: reminder)
os_log("RemindersViewController: Updated moving cell.", log: .default, type: .info)
} else {
os_log("RemindersViewController: Move triggered, but cell isn't yet visible so skipping updating the cell fields.")
}

// If we have an old and new path, then go ahead and move the cell
os_log("RemindersViewController: Moving row in table.", log: .default, type: .info)
tableView.moveRow(at: oldPath, to: newPath)
os_log("RemindersViewController: Row moved from %{public}@ to %{public}@.", log: .default, type: .info, oldPath as CVarArg, newPath as CVarArg)

// If old and new path invalid, then log that
} else {
os_log("RemindersViewController: Move triggered, but old and new path aren't filled, so ignoring it.", log: .default, type: .error)
}
break

关于ios - 在获取核心数据之后但在显示 TableView 之前,如何更新依赖于当前时间的字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55318631/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com