DocumentBasedApplication
Table of Contents |
Cocoa Document-based Applicationの作り方(基本)
Xcode 1. ファイル > New Project > Cocoa Document-based Application
Xcode 2. ターゲット > 「名前」ダブルクリック > プロパティ > 拡張子 txt または *
Xcode 3. MyDocument.xib ダブルクリック
InterfaceBuilder (以下IB).
Tools > Library 表示。
NSTextView をウィンドウにドラッグアンドドロップ。
Tools > Inspector > Scroll View Size > Auto sizing でたてよこ設定。ウィンドウリサイズで同時にリサイズするように。
File's owner (これが NSDocument のオブジェクト) 選択 > Comand + 6 (Inspector起動)
Outlet に _textView を追加。
ソースコードに反映
- File > Write Class Files > Merge。
- こわいので手書きもあり。Xcode で MyDocument.h を開き、
IBOutlet NSTextView* _textView;
Ctrl+ドラッグアンドドロップ - File's Owner => TextView画面. _textView の接続。
Xcode 4. ビルドして進行。File > Open でファイル指定はできるが、まだ読みこんだりしてはくれない。
Cocoa Document-based Applicationの作り方(続)
- (void)windowControllerDidLoadNib:(NSWindowController *) aController { [super windowControllerDidLoadNib:aController]; // Add any code here that needs to be executed once the windowController has loaded the document's window. // ファイル名の取得 NSURL *fileURL = [self fileURL]; if (! fileURL) { return; } // テキストファイルを読み込みます NSString *string = [[[NSString alloc] initWithData:[NSData dataWithContentsOfURL:fileURL] encoding:NSUTF8StringEncoding] autorelease]; if (! string) { return; } // テキストビューにテキストを設定します [_textView setString:string]; } - (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError { // テキストビューからテキストを取得します NSString* string; string = [_textView string]; // テキストをNSData型に変換します NSData* data; data = [string dataUsingEncoding:NSUTF8StringEncoding]; return data; // Insert code here to write your document to data of the specified type. If the given outError != NULL, ensure that you set *outError when returning nil. // You can also choose to override -fileWrapperOfType:error:, -writeToURL:ofType:error:, or -writeToURL:ofType:forSaveOperation:originalContentsURL:error: instead. // For applications targeted for Panther or earlier systems, you should use the deprecated API -dataRepresentationOfType:. In this case you can also choose to override -fileWrapperRepresentationOfType: or -writeToFile:ofType: instead. if ( outError != NULL ) { *outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:unimpErr userInfo:NULL]; } return nil; } - (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError { // Insert code here to read your document from the given data of the specified type. If the given outError != NULL, ensure that you set *outError when returning NO. // You can also choose to override -readFromFileWrapper:ofType:error: or -readFromURL:ofType:error: instead. // For applications targeted for Panther or earlier systems, you should use the deprecated API -loadDataRepresentation:ofType. In this case you can also choose to override -readFromFile:ofType: or -loadFileWrapperRepresentation:ofType: instead. if ( outError != NULL ) { *outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:unimpErr userInfo:NULL]; } return TRUE; }
Document-based application に Print 機能
MenuItem.xib を開く。
File > Print メニューを Ctrl+ドラッグアンドドロップ で First Responder にもっていき、print: につなげる。
どこかのクラスの print メソッドが呼ばれる。
このメソッドは現在選択している NSTextView のテキストを印刷してくれるらしい。
Document-based application の New/Open/Close 動作のすげかえ
おそらく別の手段もあるが、一番単純な方法として、 InterfaceBuilder から File > Open メニューを別のメソッド(Action)にすげかえてやればよい。 Close メニューは同様にすげかえられるが、Window 左上の Close ボタンに Action をつけられないので、 Responder chain の仕組みを利用してすげかえる。
あえて Document-based application をシングルウィンドウアプリのように動作させる方法。
MyDocument.h
- (IBAction)openFile:(id)sender; // 名前は適当にきめて、つなぐ - (IBAction)newFile:(id)sender; // 名前は適当にきめて、つなぐ - (void)windowWillClose:(NSNotification *)notification; // レスポンダチェインなので名前固定
MyDocument.m
- (IBAction)newFile:(id)sender { // テキストビューにテキストを設定します [_textView setString:@""]; [_mainWindow setTitle:@"Untitled"]; } - (IBAction)openFile:(id)sender { NSOpenPanel *sheet = [ NSOpenPanel openPanel ]; //int returnCode = [ sheet runModalForTypes: [ NSArray arrayWithObjects: @"txt", nil ] ]; int returnCode = [ sheet runModalForTypes: nil ]; if (returnCode != NSOKButton) return; // ファイル名の取得 NSString *filename = [sheet filename]; NSURL *fileURL = [NSURL fileURLWithPath: filename]; if (! fileURL) { return; } // テキストファイルを読み込みます NSString *string = [[[NSString alloc] initWithData:[NSData dataWithContentsOfURL:fileURL] encoding:NSUTF8StringEncoding] autorelease]; if (! string) { return; } // テキストビューにテキストを設定します [_textView setString:string]; // Windows のタイトルを設定します [_mainWindow setTitle:[filename lastPathComponent]]; //- (IBAction)openFile:(id)sender //{ // NSOpenPanel *panel = [NSOpenPanel openPanel]; // [panel beginSheetForDirectory:nil // file:nil // types:[NSArray arrayWithObjects:@".txt", nil] // modalForWindow:mainWindow // modalDelegate:self // didEndSelector:@selector(openFileDidEnd:returnCode:contextInfo:) // contextInfo:nil]; //} // //- (void)openFileDidEnd:(NSOpenPanel*)sheet returnCode:(int)returnCode contextInfo:(void*)contextInfo //{ // if (returnCode != NSOKButton) return; // // NSLog(@"FILES:%@",[sheet filename]); // [self setFileURL:[NSURL URLWithString:[sheet filename]]]; //} } // delegate - (void)windowWillClose:(NSNotification *)notification { //[super windowWillClose:notification]; // [NSApp termininate:nil] が window を閉じようとするため、もう一度 windowWillClose を呼ぶ。 // 2度目の windowWillClose: で呼ばれないようにデリゲート役を降りておく。 [[notification object] setDelegate:nil]; [NSApp terminate:nil]; }