0
0

More than 1 year has passed since last update.

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

Posted at

作業手順

前作の第1案にBindingsを加えて第2案を作ります。前作のフォルダーをコピーして新しいフォルダーを作り、新しい方を加工するのが楽でしょう。私は第1案のフォルダーをMyCoreData、第2案のフォルダーをMyCoreData_2としました。

Entityの設定、ViewController.h、AppDelegateのhとmはすべて共通で、作業はストーリーボードの設定とViewController.mの変更だけです。



ストーリーボードの設定

まず第1案で設定した3本のコネクションをすぺて外します。TableViewのIBOutlet、それにaddとremoveからのIBActionですね。それぞれを選択し、右側のパネルのConnectionでxみたいな印をクリックします。アシスタントエディタを開く必要はありませんよね。

View Controller Sceneに部品Array Controllerをセットします。
Array Controllerを選択し、右側のパネルのAttributeでPreserve Selectionと Select inserted Objectsのチェックを外します。
Object ControllerのModeをEntry nameとし、Entry nameをMonsterにします。Prepares Contentのチェックを外します(多分デフォールト)。Editableはデフォールトでチェックがはいっている筈です。
addボタンからArray Controllerにコントロール・ドラッグします。内訳が示されるのでaddを選択します。同様にremoveボタンからコントロール・ドラッグし、removeを選択します。

Table Column(テーブルビューの内側にある)を選択し、右側のパネルのBindingsのValueでBind toにチェックし、Array Controllerを選択します。Model Key PathをmonsterNameにします。Controller KeyはarrangedObjectsになっている筈です。

ViewController.m

ViewController.mはTableViewにコネクトされていないので、TableView関連のコードはすべて不要になります。
あとモンスターの配列は第1案ではmonstaryに格納していましたが、第2案ではArrayControllerがモンスターの配列を管理するので、monstaryも不要です。 例によってViewController.mにある元のコードをすべて削り、代わりに次のコードをこのままペーストして下さい。

//
//  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にします。





完成

使い勝手は第1案と同じで、addボタンを押すとモンスター名が追加され、removeボタンを押すと選択されたモンスターが削除されます。残念ながらaddボタンを押してもカーソルは表示されず、最下段の空白行をダブルクリックする必要があります。


すでに表示されているモンスター名をダブルクリックして編集すると、編集後の名前が保存されます。何もしていないのに、いつの間にか編集機能が追加されていました(笑)。


BindingsのおかげでViewController.mのコードは大幅に減りました。なおYouTubeでVersluisさんの完全コードレス作品を見ることができます。ただし2014年のものだそうで、多少の手直しが必要のようです。


回顧・道具としてのCoreDataとBindings

アップルの公式文書には「Bindingsによりコードの量は減るけれども、問題が起きたときのデバッグは困難である。Bindingsに手を出す前に、Bindingsを使わない通常のコーディングに十分習熟するよう強く勧める」とあります。これって意訳すれば「初心者はBindingsに手を出すな」ですよね(笑)。


実はCoreDataについてもHillegassさんは同じスタンスのようで、TableViewについて3章にわたり詳しく説明し、「後の章でCoreDataの解説をする。読者が経験豊かなプログラマーになれば、CoreDataを使って簡潔なプログラムを書くことができるけれども、その日まではCoreDataなしでTableViewを使いこなせるよう、コーディングを練習することが望ましい」と書いています。


格言風にいえば「新しい道具を欲しがるより、今の道具をマスターせよ」というところでしょうか。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0