11

Can I use NSFetchResultController on an Apple Watch to show 80 to 90 records in table?

I am using WKInterfaceTable+IGInterfaceDataTable to make use of datasource type loading methods because that seems to me simple than using NSArray.

Will NSFetchResultController help in increasing efficiency or it will make it slow?

Moshe
  • 57,511
  • 78
  • 272
  • 425
Iqbal Khan
  • 4,587
  • 8
  • 44
  • 83

3 Answers3

2

I found that NSFetchResultController is not useful at all in iWatch app because WKInterfaceTable does not support delegate method for edit, changes or delete for a single row that NSFetchResultController support in delegate. so you will have to update all data that you want to show each time so i think we should not use it.

Iqbal Khan
  • 4,587
  • 8
  • 44
  • 83
1

I used NSFetchedResultController and WKInterfaceTable for my Apple Watch application. It is true that it is not as convenient as a UITableViewController, but it is very doable. I don't have any performance issues, even in in loading 20+ rows (didn't try 80-90). Of course this is in the simulator, so I don't know how the devices themselves will behave.

Insert, update and delete you have to implement yourself, but is not that hard.

Below part of my code in the InterfaceController, with insert row as an example, but edit and delete is not more difficult:


Interface

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

Implementation

The fetching is the same as always, except that we don't assign a delegate to the resultscontroller, but save the data directly:

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;

I then use a function 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];

}

Which calls configureRowControllerAtIndex, a function that populates one row (I have two labels):

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

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

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

}

When you insert a new row, just add it manually in the managedObjectContext and in the data array:

// 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];

and regularly save the managedObjectContext:

if (![self.managedObjectContext save:&error]) {
    if (error) {
        NSLog(@"Unable to save changes.");
        NSLog(@"%@, %@", error, error.localizedDescription);
    }
}
Wouter
  • 1,568
  • 7
  • 28
  • 35
  • how you handle call back methods of NSFetchResultControllerDelegates? I think you need to calculate all rows and other things even if you add a single item because iWatch shows screen once for table and for to make a single change you need to load all table data again. – Iqbal Khan Apr 17 '15 at 07:32
  • For now I reload the table after insert, update, delete, yes. You can update an existing row with `configureRowControllerAtIndex` though (see above). Which callback methods do you want to use? `didChangeObject: atIndexPath` and so on you can replace by executing your blocks (on a seperate thread) after `configureRowControllerAtIndex` ran. That works fine in the Watch app. – Wouter Apr 17 '15 at 07:49
0

Getting NSFetchedResultsController working with WKInterfaceTable is a PITA. Hell, mapping plain arrays/dictionaries of data to WKInterfaceTable sucks. We built and open sourced a simple library to make this easier, at least making the API similar to UITableView. Just had some outside help adding support for NSFetchedResultsController. Hopefully this can help in the future!

https://github.com/Instagram/IGInterfaceDataTable

rnystrom
  • 1,906
  • 2
  • 21
  • 47