NSFetchedResultsController 用于在 Apple Watch 上显示记录?

Posted

技术标签:

【中文标题】NSFetchedResultsController 用于在 Apple Watch 上显示记录?【英文标题】:NSFetchResultController for showing records on an Apple Watch? 【发布时间】:2015-04-08 07:38:21 【问题描述】:

我可以在 Apple Watch 上使用NSFetchResultController 在表格中显示 80 到 90 条记录吗?

我使用WKInterfaceTable+IGInterfaceDataTable 来使用数据源类型加载方法,因为在我看来这比使用NSArray 简单。

NSFetchResultController 会有助于提高效率还是会降低效率?

【问题讨论】:

【参考方案1】:

我发现 NSFetchResultController 在 iWatch 应用程序中根本没有用,因为 WKInterfaceTable 不支持对 NSFetchResultController 在委托中支持的单行进行编辑、更改或删除的委托方法。所以你每次都必须更新你想要显示的所有数据,所以我认为我们不应该使用它。

【讨论】:

但它使表格的排序变得容易。【参考方案2】:

我在 Apple Watch 应用程序中使用了 NSFetchedResultControllerWKInterfaceTable。确实不如UITableViewController方便,但是非常可行。我没有任何性能问题,即使在加载 20+ 行时(没有尝试 80-90)。当然这是在模拟器中,所以我不知道设备本身会如何表现。

插入、更新和删除你必须自己实现,但没那么难。

下面是我在InterfaceController中的部分代码,以插入行为例,但编辑和删除并不难:


界面

...
@property (weak, nonatomic) IBOutlet WKInterfaceTable *interfaceTable;
@property(strong, nonatomic) NSFetchRequest *fetchRequest;
@property(strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
@property(strong, nonatomic) NSMutableArray *data;
...

实施

获取和往常一样,只是我们没有为结果控制器分配委托,而是直接保存数据:

self.fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"YourModel" inManagedObjectContext:self.managedObjectContext];
self.fetchRequest.entity = entityDescription;

[self.fetchRequest setSortDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"createdAt" ascending:YES]]];
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:self.fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];

[self.fetchedResultsController performFetch:&error];
self.data= self.fetchedResultsController.fetchedObjects;

然后我使用一个函数loadTableData:

- (void)loadTableData 
    [self.interfaceTable setNumberOfRows:[[self data] count] withRowType:@"YourCustomCell"];
    [self.interfaceTable insertRowsAtIndexes:[NSIndexSet indexSetWithIndex:[[self data] count]] withRowType:@"YourRowType"];

    for (int i = 0; i<[[self data] count];i++)
        [self configureRowControllerAtIndex:i];


调用configureRowControllerAtIndex,一个填充一行的函数(我有两个标签):

- (void)configureRowControllerAtIndex:(NSInteger)index 
    WKTableVIewRowController *listItemRowController = [self.interfaceTable rowControllerAtIndex:index];

    [listItemRowController setTitle:[[self.data[index] title] integerValue]];

    [listItemRowController setDescription:[self.data[index] description]];


插入新行时,只需在数据数组中手动​​添加managedObjectContext

// Add in managedObjectContext
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"YourModel" inManagedObjectContext:self.managedObjectContext];

YourModel *newRow = [[YourModel  alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:nil];
// Add in data array
[self.data addObject:newRow];

并定期保存 managedObjectContext:

if (![self.managedObjectContext save:&error]) 
    if (error) 
        NSLog(@"Unable to save changes.");
        NSLog(@"%@, %@", error, error.localizedDescription);
    

【讨论】:

如何处理 NSFetchResultControllerDelegates 的回调方法?我认为即使添加单个项目,您也需要计算所有行和其他内容,因为 iWatch 为表格显示一次屏幕,而要进行一次更改,您需要再次加载所有表格数据。 现在我在插入、更新、删除后重新加载表,是的。不过,您可以使用 configureRowControllerAtIndex 更新现有行(见上文)。您想使用哪些回调方法? didChangeObject: atIndexPath 等等,您可以在运行 configureRowControllerAtIndex 之后通过执行块(在单独的线程上)来替换。这在 Watch 应用中运行良好。【参考方案3】:

NSFetchedResultsControllerWKInterfaceTable 一起工作是一个PITA。地狱,将普通数组/数据字典映射到WKInterfaceTable 很糟糕。我们构建并开源了一个简单的库来简化此操作,至少使 API 类似于UITableView。刚刚获得了一些外部帮助,增加了对 NSFetchedResultsController 的支持。希望这对未来有帮助!

https://github.com/Instagram/IGInterfaceDataTable

【讨论】:

以上是关于NSFetchedResultsController 用于在 Apple Watch 上显示记录?的主要内容,如果未能解决你的问题,请参考以下文章

在 Core Data 应用程序中调用 performFetch 后,是不是需要手动更新表视图?