核心数据、UITableView 和 UISegmentedControl
Posted
技术标签:
【中文标题】核心数据、UITableView 和 UISegmentedControl【英文标题】:Core Data, UITableView, and UISegmentedControl 【发布时间】:2010-08-04 03:41:58 【问题描述】:我是使用 Core Data 的新手,并且正在使用 UITableView。我有一个带有 UISegmentedController 的工具栏,我想根据所选索引过滤 UITableView 中的项目。换句话说,假设我有一个 UITableView 来显示 Books(存储在 Core Data 中)和一个 UISegmentedController 用段来显示“English”、“Spanish”和“French”的书。
这里有什么方法可以让所有东西都连接起来?当点击其中一个段时,我在 UISegmentedControl 的目标中做什么来改变周围的东西?
对不起,如果这是一个愚蠢的问题!
【问题讨论】:
【参考方案1】:我会为每个段使用一个单独的 NSFetchedResultsController
。这将允许您利用每个段的内置缓存并提高性能。
除了 Apple 的文档(和我的书)之外,您还可以阅读我在 PragPub 杂志上的文章 Touching The Core。
【讨论】:
我不禁要说,作为已经为社区付出了这么多的人,我非常惊讶你花时间回答我关于 SO 的问题。一百万谢谢! Marcus,最干净的实现方式是什么?如果您有三个段,这将需要三个 FRC,并且在 tableview 代码中包含所有这些switch() case:
语句并不是很漂亮。也许创建一个typedef enum
,其标签对应于各个段,然后将 FRC 添加到类中适当索引处的 NSArray 中?然后你所要做的就是引用[self.frcArray objectAtIndex:[segControl selectedSegmentIndex]]
之类的东西,否则会有switch() case
。还是有更清洁的方法?
将它们作为 iVar 并拥有 currentFRC
iVar。当点击分段控件时,您切换currentFRC
指向的内容并告诉tableView 重新加载。其他所有内容都与currentFRC
对话,并检查您的委托方法,以便它们忽略任何不是来自currentFRC
的消息。【参考方案2】:
为每个过滤器使用三个不同的数组是个好主意。将它们缓存在某处,以便在用户选择过滤器时不会延迟。要从 CoreData 存储中查找您要查找的信息,请使用 NSPredicate。
【讨论】:
在 Core Data 中使用数组的代码比您需要编写的要多。最好使用NSFetchedResultsController
,因为这是它的设计目的。
适当指出:我特别喜欢 NSFetchedResultsController 使用某种缓存。我的大部分数据都是动态的,所以我想我认为大多数事情都在 NSMutableArrays 中
即使是动态数据,带有内存存储和NSFetchedResultsController
的Core Data 在几乎所有情况下都会减少代码并提高性能。值得深思。【参考方案3】:
您可以使用NSFetchedResultsController
,当您单击段时,只需设置不同的谓词并再次执行获取。
【讨论】:
阅读:developer.apple.com/iphone/library/documentation/CoreData/… 用于创建和使用 NSFetchedResultsController。 如果您只使用一个,那么您将失去其缓存的优势。最好为每个细分使用一个。【参考方案4】:我已经使用上述 Marcus 的指南实现了这一点(我是新手,所以它可能不是最好的方法)。我有一个分段控制器,其中包含“打开”、“进行中”和“关闭”三个选项。
在 ViewController.h 中,为每个段选项创建一个 iVar,并为将存储当前控制器的主控制器创建一个 iVar。
@property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
@property (nonatomic, retain) NSFetchedResultsController *inprogressFetchedResultsController;
@property (nonatomic, retain) NSFetchedResultsController *openFetchedResultsController;
@property (nonatomic, retain) NSFetchedResultsController *closedFetchedResultsController;
在 ViewController.m 中你需要创建延迟加载这些控制器的方法,所以我一共有三个。除了谓词和缓存名之外,它们基本相同,我在下面只展示了一个。
- (NSFetchedResultsController *)closedFetchedResultsController
if (_closedFetchedResultsController != nil)
return _closedFetchedResultsController;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Ticket" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"priority.name" ascending:NO];
NSArray *sortDescriptors = @[sortDescriptor];
[fetchRequest setSortDescriptors:sortDescriptors];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"status = 'Closed'"];
[fetchRequest setPredicate:predicate];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"priority.name" cacheName:@"ClosedTickets"];
aFetchedResultsController.delegate = self;
self.closedFetchedResultsController = aFetchedResultsController;
NSError *error = nil;
if (![self.closedFetchedResultsController performFetch:&error])
// Replace this implementation with code to handle the error appropriately.
// abort() 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.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
return _closedFetchedResultsController;
为您的段创建一个 IBAction,以便在更改时更改获取的结果控制器并重新加载表。
- (IBAction)statusChanged:(id)sender
switch (self.segmentControl.selectedSegmentIndex)
case 0:
self.fetchedResultsController = self.inprogressFetchedResultsController;
break;
case 1:
self.fetchedResultsController = self.openFetchedResultsController;
break;
case 2:
self.fetchedResultsController = self.closedFetchedResultsController;
break;
default:
break;
[self.tableView reloadData];
就是这样!
注意我还将这一行添加到我的 ViewDidLoad 方法中,以便它最初将正确的选项加载到 fetchedResultsController 中。
self.fetchedResultsController = self.inprogressFetchedResultsController;
【讨论】:
以上是关于核心数据、UITableView 和 UISegmentedControl的主要内容,如果未能解决你的问题,请参考以下文章
使用 NSFetchedResultsController 和核心数据移动时 UITableView 单元格消失
需要帮助在 Swift 的 UITableView 中显示核心数据
iOS - 将单元格添加到带有核心数据和 NSFetchedResultsController 的空 UITableView 部分