『Cocoa』

と言っても、Illustrator CS3〜CS5 迄のプラグインの話なんですが...
とあるプラグインで、以下のように Illustrator がログを吐いて死んじゃうので、何が原因かなぁと2日くらい悩みました。
プラグイン自体からのエラーではないので簡単にデバグで来ません。
直接の原因は、QDPlatformGlobalToLocal なんで、ここで気付けば良かったのですが、結局コメントアウトしながら原因を1つずつ確認して、リコンパイル・テストを繰り返して漸く原因を特定しました。orz

Carbon での、QuickDraw の初期化でメモリーリークがあるとかそんな感じで、良くあるトラブルだそうです。
QuickDraw の不具合なんて、今後解決される可能性は無いので、GraphicsImporter を使わない方法に変更しました。

---

Process:         Adobe Illustrator [51366]
Path:            
Identifier:      com.adobe.illustrator
Version:         367 (14.0.0)
Code Type:       X86 (Native)
Parent Process:  launchd [150]
Responsible:     Adobe Illustrator [51366]
User ID:         501

Date/Time:       2016-10-19 00:43:19.722 +0900
OS Version:      Mac OS X 10.9.5 (13F1911)
Report Version:  11
Anonymous UUID:  C441D136-C40A-94B0-141F-9E6B99B88505

Sleep/Wake UUID: BCEC1DAC-26E8-4F8E-8602-06A3D0555618

Crashed Thread:  0  Dispatch queue: com.apple.main-thread

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000063740000

VM Regions Near 0x63740000:
    __LINKEDIT             00000000400bc000-00000000400e4000 [  160K] r--/rwx SM=COW  /Volumes/VOLUME/*/Adobe Illustrator.app/Contents/Frameworks/AdobeJP2K.framework/Versions/A/AdobeJP2K
--> 
    __TEXT                 000000008feab000-000000008fede000 [  204K] r-x/rwx SM=COW  /usr/lib/dyld

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   com.apple.QD                  	0x94b0c7c5 QDPlatformGlobalToLocal + 48
1   com.apple.QD                  	0x94af5348 GlobalToLocal + 26
2   com.adobe.coretech.adm        	0x12b37f28 0x12ac2000 + 483112
3   com.adobe.coretech.adm        	0x12b13062 0x12ac2000 + 331874
4   com.adobe.illustrator         	0x0010f512 0x1000 + 1107218
5   com.adobe.illustrator         	0x0010fbde 0x1000 + 1108958
6   com.adobe.illustrator         	0x00080e11 0x1000 + 523793
7   com.apple.HIToolbox           	0x987e9d89 _InvokeEventHandlerUPP(OpaqueEventHandlerCallRef*, OpaqueEventRef*, void*, long (*)(OpaqueEventHandlerCallRef*, OpaqueEventRef*, void*)) + 36
8   com.apple.HIToolbox           	0x9863d34f DispatchEventToHandlers(EventTargetRec*, OpaqueEventRef*, HandlerCallRec*) + 1452
9   com.apple.HIToolbox           	0x9863c668 SendEventToEventTargetInternal(OpaqueEventRef*, OpaqueEventTargetRef*, HandlerCallRec*) + 386
10  com.apple.HIToolbox           	0x9863c4e0 SendEventToEventTargetWithOptions + 94
11  com.apple.HIToolbox           	0x98670459 ToolboxEventDispatcherHandler(OpaqueEventHandlerCallRef*, OpaqueEventRef*, void*) + 1757
12  com.apple.HIToolbox           	0x9863d795 DispatchEventToHandlers(EventTargetRec*, OpaqueEventRef*, HandlerCallRec*) + 2546
13  com.apple.HIToolbox           	0x9863c668 SendEventToEventTargetInternal(OpaqueEventRef*, OpaqueEventTargetRef*, HandlerCallRec*) + 386
14  com.apple.HIToolbox           	0x9864f811 SendEventToEventTarget + 88
15  com.apple.HIToolbox           	0x987e9473 ToolboxEventDispatcher + 82
16  com.apple.HIToolbox           	0x987e9333 RunApplicationEventLoop + 240
17  com.adobe.illustrator         	0x00080f83 0x1000 + 524163
18  com.adobe.illustrator         	0x000d84ab 0x1000 + 881835
19  com.adobe.illustrator         	0x000a2cd2 0x1000 + 662738
20  com.adobe.illustrator         	0x00003672 0x1000 + 9842
21  com.adobe.illustrator         	0x00003599 0x1000 + 9625
parallels_mac_osx_snowleopard.jpg

Xcode 3.2 以降は、Xcode 6.0 に各バージョンの GCC 入れる事でコンパイル可能なんだけど、流石に、Xcode 2.X はムリです。
GCC はともかく、形式が古すぎて nib のコンバートが出来ない。
それだけだったら何とか成るかも知れないけど、Rozetta が必要なユーティリティは動作しないので、Parallels Desktop for Mac 10 にゲスト OS として、Mac OS X 10.6 Server Snow Leopard  (Server 版でないとダメです) を導入してみました。
ホスト側の OS は、Mac OS X 10.9.5 Mavericks です。
XCODE で、ShiftJIS を使う場合、コメントの末尾に注意して下さい。
0x5C で終えると、エラーが出ずに、次の行をすっ飛ばすヨ!

例えば、

// 縦横入れ替え可能
hogehoge();

とかすると、hogehoge は実行されません
こんな事で何時間もデバグに使ってしまった。orz

UTF8 でも多分同様なので、UTF16 がいいかも。
XCODE の文字コードの扱いってかなりいいかげん。
日本語を使わないというのもあるけど、そんな可読性の悪いソースは書けないし...

FSSimpleCreateFile (Cocoa)

| コメント(0)
普段は、標準ライブラリ使えばいいんですが、ファイルタイプの指定はまだ必要なので、こんな感じに成ります。
POSIX パス (UTF8) から、FSRef への変換は、FSPathMakeRef 使います。

OSErr FSSimpleCreateFile(FSRef *pfsref, const char* fname, OSType creator,
OSType fileType) {
	OSErr		error = bdNamErr;
	UniChar		utfname[256];
	UniCharCount	utfsize;
	FSRef		tmpRef;
	CFStringRef	cfname;
	FSCatalogInfo	catinfo;
	FileInfo*	fileinfo;
	
	cfname = CFStringCreateWithCString(NULL, fname, kCFStringEncodingUTF8);
	utfsize = (UniCharCount)CFStringGetLength(cfname);
	
	if (utfsize) {
		CFStringGetCharacters(cfname, CFRangeMake(0, utfsize), utfname);
		if (!FSMakeFSRefUnicode(pfsref, utfsize, utfname, 
kTextEncodingUnicodeDefault, &tmpRef))
			FSDeleteObject(&tmpRef);
		
		fileinfo = (FileInfo*)catinfo.finderInfo;
		fileinfo->fileCreator = creator;
		fileinfo->fileType = fileType;
		fileinfo->finderFlags = 0;
		fileinfo->location.h = 0;
		fileinfo->location.v = 0;
		fileinfo->reservedField = 0;
		
		error = FSCreateFileUnicode(pfsref, utfsize, utfname, 
kFSCatInfoFinderInfo, &catinfo, &tmpRef, NULL);
	}
	CFRelease(cfname);
	return error;
}

ちなみにファイルの一覧を取得するのは、FSOpenIterator と、FSGetCatalogInfoBulk を使うのですが、FSRef 自体がデータ構造が公開されておりませんし、ファイル名も保持していませんので、結局、POSIX パスに変換して、保存してしまいます。
POSIX パスの場合は、ディレクトリー名が変更された場合等に対応出来ないのですが、その為に FSGetCatalogInfo 等で、FSSpec を取得するのも後ろ向きな気がしませんか?
以前はそれで問題が出る (MS Word とか) 事もあったのですが、最近はそれが普通なので、もう特に気にしなくても良い気がします。(^^;;

POSIX パスで管理する場合は、opendir を使ってファイル一覧を作成した方が楽ですね。
NSWindowController を使わないと、ややこしいのですが、何故か File Template Library に無いので、嵌りやすい。
オブジェクトライブラリの、Objects & Controrollers にも無いよ。(あったら更に混乱していたと思うけど)

iOS の場合は、モーダルビューだし、MacOS アプリの場合は、Object Controller を作成して、メインのアウトレットに繋いでおけば、簡単に使えるので、実は余り使う機会が無いからかな?

  1. Project に、Cocoa.framework を追加
    Build Phases の、Link Binary With Libraries を開いて、+ボタンを押して追加。
    Build Settings の、LLVM GCC 4.2- Language で、GCC_INPUT_FILETYPE を、Objective-C++ に設定。

  2. File Template Library の、Windows を Project Navigator にドロップして xib ファイルを作成

  3. NSWindowController のサブクラスを作成

    // SampleModalPanel.h
    
    #import <cocoa/cocoa.h>
    
    @interface SampleModalPanel : NSWindowController {
    	// IBOutlet を追加
    }
    - (IBAction)dialogOk:(id)sender;
    @end
    
    // SampleModalPanel.m
    
    #import "SampleModalPanel.h"
    
    @implementation SampleModalPanel
    - (id)initWithWindowNibName:(NSString *)nibNameOrNil {
        self = [super initWithWindowNibName:nibNameOrNil];
        if (self) {
    	// ここに初期化コードを追加
       }
        return self;
    }
    
    - (IBAction)dialogOk:(id)sender {
        [[NSApplication sharedApplication] stopModalWithCode:1];
    }
    @end
    
  4. File's Owner の Identify に指定したサブクラスを設定
    Connection の Outlets → window に、作成したパネルを接続

  5. 呼び出し側のコードはこんな感じ。

    int			result;
    SampleModalPanel*	selectFormatPanel = [[[SampleModalPanel alloc] 
    initWithWindowNibName:@"SampleModalPanel"] autorelease];
    
    result = [[NSApplication sharedApplication]
    	runModalForWindow:[selectFormatPanel window]];
    [[selectFormatPanel window] orderOut:nil];
    

※ タブ順は何も設定しないと、自動的に視点の移動が最小限に成るように設定されます。
出来れば何も設定しない良いように、UI をデザインすべきだと思います。

ページが切り替わる度に、FirstResponder の再設定が必要に成ります。
FirstResponder を指定しない、或は現在のページにはないコントロールを指定した場合は、全ての NextKeyView が無視されます。
中途半端に設定出来ない仕様だと思うのですが、少し謎な仕様です。
同じような理由で、キーチェインに、NSMatrix オブジェクトを指定しても NSMatrix 内のコントロールにフォーカスが移動...はしてくれません。
NSMatrix 内のコントロール(例えばラジオボタン)を直接指定します。
ただ、本来は、テキストフィールドだけを移動するのが Mac の仕様なので、次のテキストフィールドを指定した方が良いかも知れません。

- (void)SetupPage:(int)page {

	// タブ順の設定
	if (page == 0) {
		[mainWindow setInitialFirstResponder:AC_PH_TEXT];
		[AC_PH_TEXT setNextKeyView: AC_PW_TEXT];
		[AC_PW_TEXT setNextKeyView: AC_CH_TEXT];
		[AC_CH_TEXT setNextKeyView: AC_CW_TEXT];
		[AC_CW_TEXT setNextKeyView: AC_PH_TEXT];
	} else {
		[mainWindow setInitialFirstResponder:AF_PH_TEXT];
		[AF_PH_TEXT setNextKeyView: AF_PW_TEXT];
		[AF_PW_TEXT setNextKeyView: AF_PH_TEXT];
	}
}

※ setNextKeyView:NULL に設定すると、タブキーでの移動はそこで止まりますので、終端は NULL ではなく、最初に戻ります。
Tab キー押し下げ時等にテキストフィールドの値をチェックするのは、デリゲート(委譲)して、

- (BOOL)control:(NSControl *)control isValidObject:(id)obj;

とかすれば可能なのですが、これだとフォーカスを移動した時だけしかエラーチェックしないので、ボタンを押した時や、ページを変えた時等は無反応です。

- (BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor;

こちらも書かないとダメですね。
ちなみに、現在編集中のコントロールは、window の、firstResponder に...じゃないですよ。
ここで得られるのは、NSTextView です。
これは、fieldEditor と呼ばれているもので、各テキストフィールドの値を編集する為に共通して使われますので、ここから、NSTextField の取得は出来ません。(^^;;
編集中のコントロールを得るのは、textShouldBeginEditing で control の値を保存しておくのが一番簡単なんじゃないだろうか?

- (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor {
	NSString*	stringValue;

	// 編集前に現在のテキストを保存
	stringValue = [control stringValue];
	[stringValue getCString:_fixfield_buff maxLength:255
		encoding:NSUTF8StringEncoding];
	_fixfield_buff[255] = '¥0';
	_fixfield_control = control;
	return YES;
}

About This Article

このページには、過去に書かれたブログ記事のうちCocoaカテゴリに属しているものが含まれています。

前のカテゴリはその他です。

次のカテゴリは開発環境です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

OpenIDEnabled! What is OpenID?
Powered by Movable Type 5.04