- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我有一个 UITableView
,它显示来自 NSFetchedResultsController
的数据。 FRC 中显示的数据量各不相同,从一次提取约 20 条记录到最大一次提取约 14k 条记录不等。我遇到的问题是,如果我在 tableView 在大提取上滚动时执行提取,则会出现异常。在 cellForRowAtIndexPath
被调用时,FRC 已经更新并且那里没有数据,导致异常。
我找到了 this post ,这听起来像我遇到的情况,但我无法通过该方法解决它。
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseID, for: indexPath) as! CustomTableViewCell
// Exception occurs here
let myObject = fetchedResultsController.object(at: indexPath)
cell.myObject = myObject
return cell
}
这是堆栈跟踪:
0 CoreFoundation 0x0000000110b241e6 __exceptionPreprocess + 294
1 libobjc.A.dylib 0x000000010b820031 objc_exception_throw + 48
2 CoreData 0x000000010c2458fd -[NSFetchedResultsController objectAtIndexPath:] + 685
3 MyApp 0x000000010aaf36c5 _T011MyApp0B14ViewControllerC05tableC0So07UITableC4CellCSo0fC0C_10Foundation9IndexPathV12cellForRowAttF + 437
4 MyApp 0x000000010aaf39ec _T011MyApp0B14ViewControllerC05tableC0So07UITableC4CellCSo0fC0C_10Foundation9IndexPathV12cellForRowAttFTo + 92
5 UIKit 0x000000010cf45567 -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 783
6 UIKit 0x000000010cf45ae4 -[UITableView _createPreparedCellForGlobalRow:willDisplay:] + 74
7 UIKit 0x000000010cf0ceaa -[UITableView _updateVisibleCellsNow:isRecursive:] + 3168
8 UIKit 0x000000010cf2d7e0 -[UITableView layoutSubviews] + 176
9 UIKit 0x000000010ceb77a8 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1515
10 QuartzCore 0x000000010cc21456 -[CALayer layoutSublayers] + 177
11 QuartzCore 0x000000010cc25667 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 395
12 QuartzCore 0x000000010cbac0fb _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 343
13 QuartzCore 0x000000010cbd979c _ZN2CA11Transaction6commitEv + 568
14 UIKit 0x000000010cde22ef _UIApplicationFlushRunLoopCATransactionIfTooLate + 167
15 UIKit 0x000000010d747662 __handleEventQueueInternal + 6875
16 CoreFoundation 0x0000000110ac6bb1 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
17 CoreFoundation 0x0000000110aab4af __CFRunLoopDoSources0 + 271
18 CoreFoundation 0x0000000110aaaa6f __CFRunLoopRun + 1263
19 CoreFoundation 0x0000000110aaa30b CFRunLoopRunSpecific + 635
20 GraphicsServices 0x0000000115c2fa73 GSEventRunModal + 62
21 UIKit 0x000000010cde8057 UIApplicationMain + 159
22 MyApp 0x000000010aacd427 main + 55
23 libdyld.dylib 0x0000000111c5b955 start + 1
我欢迎提出解决此问题的建议。在 tableview
完成减速之前,我想避免做一些像禁用新获取这样的骇人听闻的事情。感谢您的阅读。
更新
作为对评论的回应,这是我对 UIFetchedResultsControllerDelegate
的实现。这是 Apple 在 documentation 中的代码:
extension ViewController: NSFetchedResultsControllerDelegate {
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>,
didChange sectionInfo: NSFetchedResultsSectionInfo,
atSectionIndex sectionIndex: Int,
for type: NSFetchedResultsChangeType) {
switch type {
case .insert:
tableView.insertSections(IndexSet(integer: sectionIndex), with: .fade)
case .delete:
tableView.deleteSections(IndexSet(integer: sectionIndex), with: .fade)
case .move:
break
case .update:
break
}
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>,
didChange anObject: Any,
at indexPath: IndexPath?,
for type: NSFetchedResultsChangeType,
newIndexPath: IndexPath?) {
switch type {
case .insert:
tableView.insertRows(at: [newIndexPath!], with: .fade)
case .delete:
tableView.deleteRows(at: [indexPath!], with: .fade)
case .update:
tableView.reloadRows(at: [indexPath!], with: .fade)
case .move:
tableView.moveRow(at: indexPath!, to: newIndexPath!)
}
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.endUpdates()
}
}
新尝试
为了回应评论,我添加了我的 NSFetchedResultsControllerDelegate
实现,这是 Apple 在文档中列出的内容。我注意到有强制解包选项,所以我加入了一些 guard
语句,并关闭了动画以备不时之需。我在做同样的事情时在同一个地方遇到了同样的崩溃。
这是更新后的委托(delegate)方法,添加了保护语句并关闭了动画:
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>,
didChange anObject: Any,
at indexPath: IndexPath?,
for type: NSFetchedResultsChangeType,
newIndexPath: IndexPath?) {
guard let indexPath = indexPath else { return }
switch type {
case .insert:
guard let newIndexPath = newIndexPath else { return }
tableView.insertRows(at: [newIndexPath], with: .none)
case .delete:
tableView.deleteRows(at: [indexPath], with: .none)
case .update:
tableView.reloadRows(at: [indexPath], with: .none)
case .move:
guard let newIndexPath = newIndexPath else { return }
tableView.moveRow(at: indexPath, to: newIndexPath)
}
}
更新 2
作为对评论的回应,这是我用来更新谓词的代码。我有一个 startDate
和 endDate
调用 updatePredicate()
的观察者。 startDate
和 endDate
在按下 segmentedControl
时更新。
// This is used to set values for searching via segmentedControl
@objc dynamic var startDate: Date?
@objc dynamic var endDate: Date?
func updatePredicate() {
// you need a start date or stop executing
guard let startDate = startDate else { return }
var predicateArray: [NSPredicate] = []
if let endDate = endDate {
let startEndPredicate = NSPredicate(format: "time >= %@ AND time <= %@", argumentArray: [startDate, endDate])
predicateArray.append(startEndPredicate)
} else {
// use the startDate's end of day if endDate is nil
let startPredicate = NSPredicate(format: "time >= %@ AND time <= %@", argumentArray: [startDate, startDate.endOfDay!])
predicateArray.append(startPredicate)
}
let sliderPredicate = NSPredicate(format: "magnitude >= %f", argumentArray: [magSlider.value])
predicateArray.append(sliderPredicate)
currentPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicateArray)
fetchResults()
}
这里是 fetchResults():
func fetchResults() {
do {
fetchedResultsController.fetchRequest.fetchBatchSize = 35
fetchedResultsController.fetchRequest.fetchLimit = 1_000
try fetchedResultsController.performFetch()
} catch let error {
print("\(error) \(error.localizedDescription)")
}
DispatchQueue.main.async {
self.tableView.reloadData()
self.tableView.setContentOffset(.zero, animated: true)
self.updateLabelsForResults()
}
}
更新 3
为回应另一条评论,以下是 FRC 声明:
private lazy var fetchedResultsController: NSFetchedResultsController<EarthquakeEntity> = {
let managedObjectContext = appDelegate.persistentContainer.viewContext
let fetchRequest: NSFetchRequest<EarthquakeEntity> = EarthquakeEntity.fetchRequest()
let dateSortDescriptor = NSSortDescriptor(key: #keyPath(EarthquakeEntity.time), ascending: false)
fetchRequest.sortDescriptors = [dateSortDescriptor]
let frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath: frcKeyPath, cacheName: nil)
frc.delegate = self
return frc
}()
最佳答案
我最终使用了 fetchLimit
,这似乎解决了我的问题。
当我执行提取时,我按如下方式使用它:
fetchedResultsController.fetchRequest.fetchLimit = 2_500
2,500 是我在不使应用程序崩溃的情况下所能达到的最大大小。
关于ios - FRC 内容更改时 UITableView 异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50770029/
我的核心数据搜索出现问题。加载后,我的整个表格都是可见的。好的。我按下搜索按钮,输入一个术语,然后按下搜索。显示正确的行。好的。 问题是当我从 TableView 返回到顶级 View (多级 Tab
我是 FRC Team 4468 的程序员,今年我们使用的是麦克纳姆轮。我们正在尝试使用这行代码用两个操纵杆控制机器人,一个用于在一个方向上移动 (mecStick),另一个用于旋转 (rotStic
在 NSFetchedResultsController (FRC) 中选择一行时,我的应用程序允许通过转到详细信息 View Controller 来更改详细信息。保存更改后,编辑的行将返回并插入到
我遇到了一些问题。我正在尝试在 Eclipse 中运行一些 FRC 插件。这个执行的程序是一个测试程序。我的目标是能够部署,但它似乎不起作用。 这些错误是什么?为什么会出现这些错误? 谢谢,Base2
我有一个 UITableView,它显示来自 NSFetchedResultsController 的数据。 FRC 中显示的数据量各不相同,从一次提取约 20 条记录到最大一次提取约 14k 条记录
我正在制作一个 iPhone 应用程序,我有一个 TableView ,它使用 frc Controller 从 Core Data 中提取数据,并显示按标题排序的内容。如果用户导航到下一个屏幕,他们
我有一个包含两个托管对象上下文的应用程序: @property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; @p
我能够将我的个人对象随机分成 2 个数组,但我不知道如何在我的 tableview 上显示这些对。这是我的随机函数。 func randomizer(array: [Person]) {
基础很简单:只需实现 在你的 TableView Controller 中。这是 an adequate tutorial . 诀窍是要意识到有两个 Controller :一个 TableView
目标:使用 FRC,按 startDate 对 Section 的 进行排序,这是一个 NSDate 属性,但要 今天的日期 Section 出现在 Upcoming 日期 Section 之前。 我
我有一个 View Controller ,名为 ScorecardViewController ,其中包含 UITableView ,称为 HolesTable ,它由 FetchedResults
我在两个 TableView Controller 中实现核心数据。第一个显示银行名称、城市和州,第二个显示银行的详细信息,如 zip 、截止日期等。因此,我的模型中有两个实体。第一个称为“BankI
这是我的结构: 我有一个名为“元素”的实体。并且Element包含多个时间戳。时间戳是一个与元素有关系的实体。 Element Time Stamp 1 Time Stamp 2 T
我已经更新了这个问题,因为我发现了这个问题的另一个关键。似乎当我向 CoreData 添加内容时,tableview 不会重新加载数据,即使我可以打印出 CoreData 保存的对象。所以我知道数据是
我是一名优秀的程序员,十分优秀!