我已经使用 NSFetchedResultsController 实现了一个 UITableView,以从 sqllite 数据库加载数据。我将数据库从设备下载到模拟器,所以两者都是一样的。
我观察到奇怪的行为,当在模拟器上运行时,tableview 填充了正确数量的单元格(在初始基本情况下:一个单元格);然而,当我在设备上运行相同的代码时,numberOfObjects 返回 2,并且 tableview 显示两个(相同/重复的)单元格。
当我检查 sqllite 文件时,其中确实只有 1 个对象/行...
我按照示例代码进行实现,没有做任何特别的事情。
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSInteger count = [[fetchedResultsController sections] count];
if (count == 0) {
count = 1;
}
return count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSInteger numberOfRows = 0;
if ([[fetchedResultsController sections] count] > 0) {
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
numberOfRows = [sectionInfo numberOfObjects];
}
NSLog(@"SwoopListTableViewController::numberOfRowsInSection - numberOfRows:%d", numberOfRows);
return numberOfRows;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Dequeue or if necessary create a SwoopTableViewCell, then set its Swoop to the Swoop for the current row.
static NSString *SwoopCellIdentifier = @"SwoopCellIdentifier";
SwoopTableViewCell *SwoopCell = (SwoopTableViewCell *)[tableView dequeueReusableCellWithIdentifier:SwoopCellIdentifier];
if (SwoopCell == nil) {
SwoopCell = [[[SwoopTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SwoopCellIdentifier] autorelease];
SwoopCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
[self configureCell:SwoopCell atIndexPath:indexPath];
return SwoopCell;
}
和
- (NSFetchedResultsController *)fetchedResultsController {
// Set up the fetched results controller if needed.
NSLog(@"SwoopListTableViewController::fetchedResultsController - started");
if (fetchedResultsController == nil) {
if (managedObjectContext == nil)
{
managedObjectContext = [(SwoopAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSLog(@"SwoopListTableViewController::fetchedResultsController - set managedObjectContext");
}
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Swoop" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"creationDate" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
}
return fetchedResultsController;
}
我很困惑为什么相同的代码和相同的数据库会在模拟器(按预期工作)和设备(3GS - 显示重复的表格单元格)上表现出不同的行为。任何人都可以帮助/解释/提供一些关于我应该看什么的见解吗?
非常感谢, 埃里克
** 编辑 1: ** 我对 NSCoreData 和 NSFetchedResultsController 进行了更多调试。似乎 fetchRequest 确实从 managedContext 返回了一个重复的对象。这是代码和相应的控制台输出:
Controller 代码:
- (void)viewDidLoad {
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:0];
NSLog(@"SwoopListTableViewController::viewDidLoad - sectionInfo objects:%@", [sectionInfo objects] );
}
控制台输出:
2011-05-14 17:54:53.388 Swoop[1471:307] SwoopListTableViewController::viewDidLoad - sectionInfo objects:(
"<Swoop: 0x187d60> (entity: Swoop; id: 0x186480 <x-coredata://A9FF2CC0-77EE-4EFF-A3A6-5F085AA9CCAC/Swoop/p2> ; data: <fault>)",
"<Swoop: 0x187d60> (entity: Swoop; id: 0x186480 <x-coredata://A9FF2CC0-77EE-4EFF-A3A6-5F085AA9CCAC/Swoop/p2> ; data: <fault>)",
"<Swoop: 0x188180> (entity: Swoop; id: 0x143a60 <x-coredata://A9FF2CC0-77EE-4EFF-A3A6-5F085AA9CCAC/Swoop/p1> ; data: <fault>)"
)
我觉得很奇怪,sectionInfo 中的前两个对象都有相同的内存地址“0x187d60”,并且都有相同的 x-coredata 'path': "//A9FF2CC0-77EE-4EFF-A3A6-5F085AA9CCAC/Swoop/p2"...有人可以解释这是什么意思,或者可能发生了什么吗?
谢谢, 埃里克
最佳答案
在对 NSCoreData 进行了更多阅读和挖掘之后,问题似乎是由于设备上内存管理方式的特殊性(我假设相同的内存约束/管理将应用于模拟器,但我猜两者之间存在差异)——具体来说,如果在出现内存不足警告时卸载 View ,则在再次重新加载 View 时将执行提取,这可能会导致重复条目。
我发现以下链接中描述的问题/解决方案解决了我遇到的问题:
Duplicate NSManagedObject with NSFetchedResultsController
另一方面,了解如何通过将此参数传递给应用程序来启用不同级别的 NSCoreData 日志记录也很有帮助:
-com.apple.CoreData.SQLDebug 1
在这里阅读更多:
从 Apple Developer 库中,请参阅“Troubleshooting Core Data:Debugging Fetching”
要通过 xcode 添加参数,请参阅本页上的“为命令行程序提供启动参数”http://www.meandmark.com/xcodetips.html
关于iphone - NSFetchedResultsController numberOfObjects 在设备上运行时返回附加(重复),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5975019/