objective-cの文字列キーの定義

ヒレガス本第四版の第13章を読んでの感想。 一昔前は、プリプロセッサマクロの#defineを使用していた。最近はグローバル変数を使うのが定石らしい。

XXXXXX_KEYを定義したい場合には、

*.hに

extern NSString* const XXXXXX_KEY

*.mに

extern NSString* const XXXXXX_KEY = @"XXXXXX_KEY";

と書くのがお作法のようです。

自分は#defineのやり方とコチラのやり方を行ったり来たりしていたが、今後はグローバル変数のやり方に統一するつもり。

ヒレガス本 12章 課題

課題は、NSBundleを利用してnibをロードし独自のAboutPanelを表示しろとの事。

早速NSBundleを使ってNibをロードしようと、

[NSBundle loadNibNamed: owner:]

を使おうとしたらDeprecatedとの事。

仕方が無いので、NSNibを使用して以下のように書いた。

- (IBAction) showAbouPanel:(id)sender
{
    if( !aboutPane )
    {
        NSNib*    theAboutPanelNib;

        theAboutPanelNib = [[NSNib alloc] initWithNibNamed:@"aboutPanel.nib"
                                                    bundle:nil];

        NSArray* theTopLevelObject;

        if( [theAboutPanelNib instantiateWithOwner:self
                                      topLevelObjects:&theTopLevelObject] )
        {
            NSLog(@"aboutPanel loaded from nib. %@", theTopLevelObject);

        }
    }

    [aboutPane makeKeyAndOrderFront:sender];
}

プロジェクトファイルは、 RaiseMan_NibAndWindowController に置いておきます。

ヒレガス本 11章 課題

課題を行ってみてミスを2つした。

  • TableViewに何も表示されない

理由は、NSArrayControllerのManaged Object Contextを設定をし忘れていた。

Managed Object ContextをFile’s OwnerのManagedObjectContextにbindingしする必要があったのに設定を忘れていた。

  • Make/ModelとPriceの編集が出来なかった

理由は、それぞれのTextViewで、Binding PropatyのConditionally Sets EditableをONにしていなかった事が原因だった。

課題その物の、新しいレコードを追加してすぐに編集を開始するには以下のコードを追加した。

//
//  CarArrayController.h
//  CarLot

#import <Cocoa/Cocoa.h>

@interface CarArrayController : NSArrayController
{
    IBOutlet NSTableView* tableView;
}

@end
//
//  CarArrayController.m
//  CarLot

#import "CarArrayController.h"

@implementation CarArrayController

// managedObjectContextに変化があれば managedObjectContextObjectsDidChange:を呼び出し
// tableを編集状態にする

- (void) awakeFromNib
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(managedObjectContextObjectsDidChange:)
                                                 name:NSManagedObjectContextObjectsDidChangeNotification
                                               object:[self managedObjectContext]];
}

// 終了時にobservingを停止する
- (void) dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void) managedObjectContextObjectsDidChange:(NSNotification*)inNotification
{
    NSManagedObject* theObject = [[[inNotification userInfo] valueForKey:NSInsertedObjectsKey] anyObject];

    if( theObject )
    {
        NSUInteger theRow = [[self arrangedObjects] indexOfObject:theObject];

        [tableView editColumn:0
                          row:theRow
                    withEvent:nil
                       select:YES];
    }
}

// これはヒレガス本そのまま
- (id) newObject
{
    id theNewObject = [ super newObject];

    NSDate* theNow = [NSDate date];

    [theNewObject setValue:theNow
                    forKey:@"datePurchased"];

    return theNewObject;
}

@end

しかし、Undo/Redoがうまく働いていないように見える。Undo/Redoで内部データとTableViewのレコードがうまく連動していない。

CoreDataだとUndo/Redoを自動で行うので手を入れなくて良いと思っていたが違うようだ。

前々回の、Cocoa勉強会でCoreDataのUndoManagerについて平井さんが発表していた気がしたのでハンドセットを読み返した。 しかし、デバッグのやり方しか書いていない。

CoreDataの基礎の章なので深くは追求しない事にした。

NSArchiverはdeprecated

ヒレガス本でアーカイブ化の章を読んで、NSArchiverの事が一言も出ていなかった。 不思議に思い、ググると Cocoaでのアーカイブとシリアライズ機能 アーカイブ編 が見つかる。

10.3以降はNSArchiverはdeprecatedなのでNSKeyedArchiverを使うべきとの事。

要点は、

  • 新規プリケーションにはNSKeyedArchiverを使え。NSArchiverは後方互換性の為だけに残されている。
  • setVersionも不要。NSKeyedArchiverを使えば必要ない。

との事。歳はとりたくないなぁ。