iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど
MainStoryboard.storyboardの中身を空にして、Navigation Controllerを配置する。デフォルトで、テーブル・ビューが組み込まれているので、これを利用する。
Root View ControllerのCustom Classを自分のViewControllerに変更する(説明の順番が前後してしまったが、自分のViewControllerの親クラスをUITableViewControllerに変更しておく必要はあると思う)。
そして、Table View CellのIdentifierをCellに変更しておく。このIdentifierを後のコードで利用するので。
独自のViewControllerクラスのヘッダーをテーブル・ビューとCoreDataに対応させる。
@interface ViewController : UITableViewController &tl;NSFetchedResultsControllerDelegate≷
@property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
@property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@end
AppDelegateクラスの、アプリケーション起動時に呼ばれるメソッドで、管理オブジェクト・コンテキストをビュー・コントローラーに渡すコードを追加する。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
ViewController *controller = (ViewController *)navigationController.topViewController;
controller.managedObjectContext = self.managedObjectContext;
return YES;
}
ViewControllerクラスの、CoreDataとテーブル・ビュー対応のコードは、雛形のコードをほぼそのまま流用している。現在のXcodeの新規プロジェクトで生成される雛形のコードでは、NSFetchedResultsControllerが使われていて、データとテーブル・ビューの連動が自動で行われて便利だが、独自のデータ管理の仕組みを持っている場合、それを介さないでコントロールされるので、これについては、今後の課題と考えている。
@interface ViewController ()
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath;
@end
@implementation ViewController
@synthesize fetchedResultsController = __fetchedResultsController;
@synthesize managedObjectContext = __managedObjectContext;
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.leftBarButtonItem = self.editButtonItem;
UIBarButtonItem *addButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self action:@selector(insertNewObject:)];
self.navigationItem.rightBarButtonItem = addButton;
}
…
- (void)insertNewObject:(id)sender
{
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name]
inManagedObjectContext:context];
[newManagedObject setValue:[NSDate date] forKey:@"timeStamp"];
NSError *error = nil;
if (![context save:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [[self.fetchedResultsController sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id sectionInfo = [[self.fetchedResultsController sections]
objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
[context deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];
NSError *error = nil;
if (![context save:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return NO;
}
- (NSFetchedResultsController *)fetchedResultsController
{
if (__fetchedResultsController != nil) {
return __fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event"
inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timeStamp" ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:nil
cacheName:@"Master"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return __fetchedResultsController;
}
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id )sectionInfo
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
{
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath]
atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView endUpdates];
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [[object valueForKey:@"timeStamp"] description];
}
@end