HillegassさんのCoreData・簡易版(第2案)

## 作業手順 
[前作の第1案](https://qiita.com/streaker/items/ad7220a49dd815d2e704)にBindingsを加えて第2案を作ります。前作のフォルダーをコピーして新しいフォルダーを作り、新しい方を加工するのが楽でしょう。私は第1案のフォルダーをMyCoreData、第2案のフォルダーをMyCoreData_2としました。<br>
Entityの設定、ViewController.h、AppDelegateのhとmはすべて共通で、作業はストーリーボードの設定とViewController.mの変更だけです。
<br>
<br>
<h2>ストーリーボードの設定</h2>
まず第1案で設定した3本のコネクションをすぺて外します。TableViewのIBOutlet、それにaddとremoveからのIBActionですね。それぞれを選択し、右側のパネルのConnectionでxみたいな印をクリックします。アシスタントエディタを開く必要はありませんよね。<br><br>
View Controller Sceneに部品Array Controllerをセットします。<br>
Array Controllerを選択し、右側のパネルのAttributeでPreserve Selectionと
Select inserted Objectsのチェックを外します。<br>
Object ControllerのModeをEntry nameとし、Entry nameをMonsterにします。Prepares Contentのチェックを外します(多分デフォールト)。Editableはデフォールトでチェックがはいっている筈です。<br>
addボタンからArray Controllerにコントロール・ドラッグします。内訳が示されるのでaddを選択します。同様にremoveボタンからコントロール・ドラッグし、removeを選択します。<br><br>
Table Column(テーブルビューの内側にある)を選択し、右側のパネルのBindingsのValueでBind toにチェックし、Array Controllerを選択します。Model Key PathをmonsterNameにします。Controller KeyはarrangedObjectsになっている筈です。
<br><br>
<h2>ViewController.m</h2>
ViewController.mはTableViewにコネクトされていないので、TableView関連のコードはすべて不要になります。<br>
あとモンスターの配列は第1案ではmonstaryに格納していましたが、第2案ではArrayControllerがモンスターの配列を管理するので、monstaryも不要です。
例によってViewController.mにある元のコードをすべて削り、代わりに次のコードをこのままペーストして下さい。
<br>
<br>

```objc
//
//  ViewController.m
//  MyCoreData
//
//  Created by Myself on 2022/03/25.
//  Copyright © 2022 None. All rights reserved.
//


#import "ViewController.h"

  ViewController *viewctrl_ptr = nil;	/* (referenced by 'AppDelegate') */





@implementation ViewController

{
 
// __weak IBOutlet NSTableView *tbl_view_ptr;	<--(not used)
 
 IBOutlet NSArrayController *ary_ctrl_ptr;
 
 
#pragma mark global variables within ViewController

  const NSString *MYENTITY;	/* for @"Monster" */
  const NSString *THE_NAME;	/* for @"monsterName" */

  AppDelegate *parent_ptr;

  NSManagedObjectModel *my_mom;
  NSPersistentStoreCoordinator *my_psc;
  NSManagedObjectContext *my_moc;
  NSFetchRequest *my_fetch;

//  NSMutableArray<NSManagedObject *> *monstary;	<--(not used)
//  NSInteger nbr_rows;		<--(not used)
//  BOOL editflag;		<--(not used)
}





#pragma mark initializers

- (void)viewDidLoad

{ [super viewDidLoad];

  MYENTITY = @"Monster";
  THE_NAME = @"monsterName";

  viewctrl_ptr = self;		/* set public variable */

//  tbl_view_ptr.delegate = self;
//  tbl_view_ptr.dataSource = self;

//  monstary = [[NSMutableArray alloc] init];	/* initialize monster array */
//  nbr_rows = 0;			/* no row in table-view */
//  editflag = NO;		/* not editing */
} // viewDidLoad





- (void)setRepresentedObject:(id)representedObject

{ [super setRepresentedObject:representedObject];

	// Update the view, if already loaded.
} // setRepresentedObject





#pragma mark public functions

- (void)setParent_ptr:(AppDelegate *)myparent

	/* called by 'AppDelegate' */

{ parent_ptr = myparent;
  NSLog(@"parent ready");
} // setParent_ptr





-(void)set_pc

	/* set persistent-container variables */
	/* called by 'AppDelegate' */
	/* called after AppDelegate ready */

{ [self initcore];		/* initialize core data */
//  [tbl_view_ptr reloadData];	/* display registered Monsters */
} // set_pc





- (void)save_ary

	/* save the whole managed object context */
	/* called by 'AppDelegate' */

{ NSError *errorptr;
  BOOL myresult;

  errorptr = nil;
  myresult = [my_moc save: &errorptr];
  if ( ( myresult == NO ) || ( errorptr != nil ) )
    NSLog(@"managed object context save error");
  else
    NSLog(@"managed object context successfully saved");
} // save_ary





#pragma mark private function

	/* (empty) */





#pragma mark event handlers

	/* (empty) */




#pragma mark core data functions

- (void)initcore

	/* initialize core data */
	/* note: 'my_mom' and 'my_psc' not used */

{ NSArray *temp_ary;
  NSError *errorptr;

  NSAssert(parent_ptr.persistentContainer != nil, @"persistentContainer failed");

  my_mom = parent_ptr.persistentContainer.managedObjectModel;
  NSAssert(my_mom != nil, @"managed object managedobjectmode failed");
  my_psc = parent_ptr.persistentContainer.persistentStoreCoordinator;
  NSAssert(my_psc != nil, @"persistent store coordinator failed");
  my_moc = parent_ptr.persistentContainer.viewContext;
  NSAssert(my_moc != nil, @"managed object context failed");

	// array-controller's managed object
	// set here

  ary_ctrl_ptr.managedObjectContext = my_moc;

  my_fetch = [[NSFetchRequest alloc] initWithEntityName: MYENTITY];

  errorptr = nil;	/* (unnecessary ... result not used) */
  temp_ary = [my_moc executeFetchRequest: my_fetch error: &errorptr];
  NSAssert(temp_ary != nil, @"initial fetch failed");
  if ( temp_ary.count == 0 )
    NSLog(@"no monster in sandbox");
  else
  { NSLog(@"%d monster(s) in sandbox", (unsigned int)temp_ary.count);

	// ArrayController (not monstary) gets monsters

//    [monstary addObjectsFromArray: temp_ary];
      [ary_ctrl_ptr addObjects: temp_ary];
  }
} // initcore





- (void)createOneWithName: (NSString *)new_name

	/* create (and save) one entity */

{ //	(not used)
} // createOne





#pragma mark delegate and datasource

	/* (empty) */

@end

```

最後にアシスタントエディタを使ってストーリーボードとViewController.mを並べ、Array ControllerのIBOutletを作ります。名前はary_ctrl_ptrにします。
<br>
<br>
<br>

<h2>完成</h2>

使い勝手は第1案と同じで、addボタンを押すとモンスター名が追加され、removeボタンを押すと選択されたモンスターが削除されます。残念ながらaddボタンを押してもカーソルは表示されず、最下段の空白行をダブルクリックする必要があります。<br><br>
すでに表示されているモンスター名をダブルクリックして編集すると、編集後の名前が保存されます。何もしていないのに、いつの間にか編集機能が追加されていました(笑)。<br><br>
BindingsのおかげでViewController.mのコードは大幅に減りました。なおYouTubeで[Versluisさん](https://pinkstone.co.uk/how-to-bind-an-nsarraycontroller-to-an-nstableview/)の完全コードレス作品を見ることができます。ただし2014年のものだそうで、多少の手直しが必要のようです。
<br><br>
## 回顧・道具としてのCoreDataとBindings
[アップルの公式文書](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/TableView/PopulatingViewTablesWithBindings/PopulatingView-TablesWithBindings.html#//apple_ref/doc/uid/10000026i-CH13-SW1)には「Bindingsによりコードの量は減るけれども、問題が起きたときのデバッグは困難である。Bindingsに手を出す前に、Bindingsを使わない通常のコーディングに十分習熟するよう強く勧める」とあります。これって意訳すれば「初心者はBindingsに手を出すな」ですよね(笑)。<br><br>
実はCoreDataについてもHillegassさんは同じスタンスのようで、TableViewについて3章にわたり詳しく説明し、「後の章でCoreDataの解説をする。読者が経験豊かなプログラマーになれば、CoreDataを使って簡潔なプログラムを書くことができるけれども、その日まではCoreDataなしでTableViewを使いこなせるよう、コーディングを練習することが望ましい」と書いています。<br><br>
格言風にいえば「新しい道具を欲しがるより、今の道具をマスターせよ」というところでしょうか。