|
- 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 でファイルのオープンを処理しているからなんだろうけど、気づきにくいわな。
|