Geometry 関数
NSBundle
NSDictionary
NSFileManager
NSMutableAttributedString
NSNumber
NSScanner
NSString
NSTimer
Graphic 関数
NSApplication
NSBezierPath
NSCell
NSColor
NSCursor
NSCustomImageRep
NSDocument
NSDocumentController
NSDragging
NSEvent
NSFontManager
NSGraphicsContext
NSImage
NSMenu
NSOutlineView
NSPanel
NSPopUpButton
NSResponder
NSScrollView
NSString 追加
NSTableColumn
NSTableView
NSTextStorage
NSTextView
NSToolbar
NSView
NSWindow
NSWorkspace
その他
-main() から直接 Cocoa API を呼び出す
-Class の名前を NSString で取り出す
-オブジェクトの名前を C 文字列で取り出す
-プロパティリストを変更可能な形に変える
-アプリケーションの実行パスを取得する
-ドキュメント・ベース・アプリケーションで、自動的に新規ファイルを開かない
.nib ウィンドウ
Views パレット
クラス
インスタンス変数
メソッド
CFXML
Carbon Event
Carbon Graphics
Cocoa で日本語
メソッド
その他
-main() から直接 Cocoa API を呼び出す
-Class の名前を NSString で取り出す
-オブジェクトの名前を C 文字列で取り出す
-プロパティリストを変更可能な形に変える
-アプリケーションの実行パスを取得する
-ドキュメント・ベース・アプリケーションで、自動的に新規ファイルを開かない

- Miscellaneous-
その他

Miscellaneous - その他
main() から直接 Cocoa API を呼び出す
Keywords: Command line, NSAutoreleasePool

Classic な MacOS プログラミングと比べて、MacOS X のプログラミングのさいに、やっぱり便利なものはなにか?それは、標準のコマンドラインの存在だと思うんだ。もちろん、アプリケーションとして仕上げるときに使わないとしても、デバッグの段階では便利だよね。

でも、いざコマンドラインを使ってみると、問題があることに気付くと思うんだ。C や C++ の標準ライブラリ(stdio とか)だけのときは特に問題ない。でも、AppKit や Foundation Kit のクラスを使おうとすると、"_NSAutoreleaseNoPool()" っていうエラーコメントが表示されないかい?

AppKit ではメモリ管理に、参照カウンタを用いた、自動的にオブジェクトが削除される管理を行っている。それを行うのが NSAutoreleasePool だ。Project Builder でテンプレートを使ってアプリを作る場合は、自動的に NSAutoreleasePool が作られるから、気にしなくてよろしい。でも、コマンドラインのアプリを作るときは、自分で作らなくちゃいけないんだ。次のようにする。

Command line application (sample)
int main(int argc, const char* argv[]) {
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    ...
    // Cocoa methods
    ...
    [pool release];
    return 0;
}

まず、NSAutoreleasePool のインスタンスを作る。そのあとで、AppKit や FoundationKit の関数を呼び出す。最後に NSAutoreleasePool の release を呼び出して、オブジェクトを削除する。これで OK だ。


Miscellaneous - その他
Class の名前を NSString で取り出す
Keywords: class, NSStringFromClass

ある id 型の変数があったとしよう。さて、こいつのクラスはいったい何か調べてみよう!まず、Class 型を表示する。id に代入されているものが、NSObject から派生されているものならば(たいていはそうだ)、class メソッドを使うことができる。class メソッドは、NSObject の protocol として、定義されている。

FoundationKit/NSObject.h
- (Class)class;

Class 型が得られたら、次はどうするか?こいつの名前を知りたいよね。そのためには、NSStringFromClass() という、そのものずばりの関数がある。

FoundationKit/NSObjCRuntime.h
FOUNDATION_EXPORT NSString *NSStringFromClass(Class aClass);

これで、ある id 型のクラス名を表示させることができるぞ。

Display class name (sample)
void displayClass() {
    id anUnknownItem;
    Class unknownClass = [id class];
    NSString* classNameStr = NSStringFromClass(unknownClass);
    printf("class name is %s.¥n", [classNameStr cString]);
}

Miscellaneous - その他
オブジェクトの名前を C 文字列で取り出す
Keywords: NAMEOF, object_getClassName

オブジェクトのクラスの名前を表示するもう 1 つの方法。Objective-C runtime に用意されている NAMEOF マクロを使うんだ。

objc/obhc.h
#define NAMEOF(obj)     object_getClassName(obj)

これは object_getClassName() っていう関数を呼び出している。この関数の定義はこうだ。

FoundationKit/NSObjCRuntime.h

OBJC_EXPORT const char *object_getClassName(id obj);

こいつがクラスの名前を返す。NSStringFromClass() との違いは、NSString 型で返すか、C string 型で返すか、っていうとこね。


Miscellaneous - その他
プロパティリストを変更可能な形に変える
Keywords: plist, NSMutableArray, NSMutableDictionary

プロパティリストを変更可能な形に変える形式は、NSArray や NSDictionary などでできてるリスト。便利なのは、こいつは文字列で保存しておくことができるんだ。ファイルからの読み出しも簡単。NSString の propertyList で変換できる。

だけど、こいつを使ってとりだすと、変更不可の形(immutable)で取り出されるんだ。これを変更可能(mutable)に変えてみよう。ここでは NSArray を NSMutable に、NSDictionary を NSMutableDictionary に変える。

(sample)
id MakeMutablePlistCopy(id plist)
{
    id copyPlist;
    
    if ([plist isMemberOfClass:[NSArray class]]) {
        copyPlist = MakeMutableArrayCopy(plist);
    }
    else if ([plist isMemberOfClass:[NSDictionary class]]) {
        copyPlist = MakeMutableDictionaryCopy(plist);
    }
    else {
        copyPlist = [plist copy];
    }
    
    return copyPlist;
}

NSMutableArray* MakeMutableArrayCopy(NSArray* array)
{
    id  copy;
    int i;
    
    // Make copy
    copy = [[NSMutableArray alloc] initWithArray:array copyItems:YES];
    [copy autorelease];
    
    // Enumerate object
    for (i = 0; i < [copy count]; i++) {
        id	object;
        
        object = [copy objectAtIndex:i];
        if ([object isMemberOfClass:[NSArray class]]) {
            [copy replaceObjectAtIndex:i 
                            withObject:MakeMutableArrayCopy(object)];
        }
        else if ([object isMemberOfClass:[NSDictionary class]]) {
            [copy replaceObjectAtIndex:i 
                            withObject:MakeMutableDictionaryCopy(object)];
        }
    }
    
    return copy;
}

NSMutableDictionary* MakeMutableDictionaryCopy(NSDictionary* dict)
{
    id            copy;
    id            key;
    NSEnumerator* enumerator;
    
    // Make copy
    copy = [[NSMutableDictionary alloc] initWithDictionary:dict copyItems:YES];
    [copy autorelease];
    
    // Enumerate object
    enumerator = [copy keyEnumerator];
    while (key = [enumerator nextObject]) {
        id	object;
        
        object = [copy objectForKey:key];
        if ([object isMemberOfClass:[NSArray class]]) {
            [copy setObject:MakeMutableArrayCopy(object) 
                            forKey:key];
        }
        else if ([object isMemberOfClass:[NSDictionary class]]) {
            [copy setObject:MakeMutableDictionaryCopy(object) 
                            forKey:key];
        }
    }
    
    return copy;
}

やっていることは非常に簡単で、property list の中のオブジェクトを 1 つずつたどっていって、NSArray がでてきたら initWithArray:copyItems: で、NSDictionary が出てきたら initWithDictionary:copyItems: でコピーしてやるだけだ。これで、とりだした plist を編集できるよ。

■関連リンク:
プロパティリスト表示を取り出す、その逆も (NSDictionary)


Miscellaneous - その他
アプリケーションの実行パスを取得する
Keywords: bundlePath

Mac OS X では、アプリケーションはバンドルになっている。だから、実行中のアプリケーションのパスを調べたいときは、NSBundle を使う。NSBundle には、バンドルのディレクトリを調べる bundlePath や、実行ファイルのパスを調べる executablePath が用意されている。

Foundation/NSBundle
- (NSString*)bundlePath;
- (NSString*)executablePath;

次のように使えばいい。バンドルのディレクトリ、つまりアプリケーションファイル(.app ディレクトリ)のパスを調べるコードだ。

(sample)
    [[NSBundle mainBundle] bundlePath];

Miscellaneous - その他
ドキュメント・ベース・アプリケーションで、自動的に新規ファイルを開かない
Keywords: applicationShouldOpenUntitledFile:

(掲示板に書き込んでくれた、ななしさん、ありがとうございました。)

ドキュメント・ベース・アプリケーションは、デフォルトだと、アクティブになったときにドキュメントが開いていなかったら、自動的に新規ドキュメントを作成するでしょ。あれ、うざったいときがあるよね。これをやめさせるには、NSApplication の delegate で、applicationShouldOpenUntitledFile: を実装する。開きたくなかったら、NO を返せばいい。

(sample)
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication*)sender
{
    return NO;
}

NSApplication でファイルのオープンを処理しているからなんだろうけど、気づきにくいわな。



[Home] [Download] [Archives] [BBS] [Cocoa Programming Tips 1001] [Core Foundation の秘密] [Safari Developer Center] [はじめてのブラウザのつくり方] [Sketch BP] [スクリーンセイバーを作ろう] [Objective-C 最適化] [Authorization API 完全理解] [Mac OS X Programming Books Review] [オブジェクト指向の言語比較論] [panther-dev]

mailto: mkino@xd5.so-net.ne.jp