MOSA Developer News[MOSADeN=モサ伝]第134号
2004-10-26
目次
- SqueakではじめるSmalltalk入門 第16回 鷲見 正人
- 小池邦人の「Carbon API 徒然草」
- 「Behind the WebObjects」 第30回 田畑 英和
- ニュース・解説
SqueakではじめるSmalltalk入門 第16回 鷲見正人
本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。今回は、前回作成したBankAccountクラスにメソッドを追加してゆきます。
作業状態を凍結した仮想イメージを使ってシステムを起動します。ちょうどインスペクトした状態にあるa BankAccountに、無駄とは承知でbalance: 1000という“彼”の知らないメッセージを送って反応を見てみることにします。インスペクタのワークスペース(下のペイン)で、
self balance: 1000
とタイプして入力し、do it (cmd-D)してみてください。
[fig.A]とりあえずメッセージを送ってみる
http://squab.no-ip.com:8080/mosaren/uploads/16a.png
まず、コンパイラがスペルミスを犯していないかとお節介を焼いてくれます。
[fig.B]コンパイラが起動するスペルチェッカ
http://squab.no-ip.com:8080/mosaren/uploads/16b.png
いや、そんなことはない、という意思表示を込めて、項目の先頭にあるbalance:を選択しましょう。コンパイルは通りますが、実際のメッセージ送信の結果、a BankAccountは#balance:というセレクタからなるメッセージを受け付けられないとノーティファイア(ピンクの横長のウインドウ)を出します。
[fig.C]メッセージに応答できないことを示すノーティファイア
http://squab.no-ip.com:8080/mosaren/uploads/16c.png
では、a BankAccountが、このメッセージを理解できるようにBankAccountクラスに改めて#balance:メソッドを定義することにします。ブラウザをクリックしてアクティベートし、メッセージカテゴリペイン(上段右から2番目)のno messagesをクリックして選択します。すると、コードペインにメソッド記述のためのテンプレートが現われます。マウスポインタをコードペインに移動するとテンプレートは選択されていることが分かるので、キーボードのdeleteキーを使って消してしまってください。
[fig.D]メソッド記述のためのテンプレート
http://squab.no-ip.com:8080/mosaren/uploads/16d.png
うまく消えたら(消えないときは、マウスポインタの位置を確認してください。コードペインの区画を指していますか?)次のコードをタイプしてシフト黄ボタンメニュー(コードペインをshift + optionクリック、あるいは、黄ボタンメニューからmore…)からpretty printを選択してフォーマットを整えた後、accept (cmd-S)します。
balance: x
balance _ x
[fig.E]シフト黄ボタンメニューのpretty print
http://squab.no-ip.com:8080/mosaren/uploads/16e.png
1行目の太字になっている行は「メッセージパターン」と呼ばれるもので、セレクタ(メソッド名)と、メッセージ送信時に添えられたパラメータ(引数)を束縛するための「パラメータ変数」の宣言文を兼ねます。コード本体は2行目以降(この場合、2行目のみ)です。インスタンス変数balanceに、パラメータ引数xの値を代入する簡単なコードであることは、一目でお分かりいただけると思います。
acceptと同時にあなたのイニシャルを要求するfill in the blankが現われることがあります。これは、メソッドごとに誰が作成/改変したかを記録する際に使われます(システムに加えられた改変履歴情報の扱いについては追って解説する予定です)。
適当なイニシャルを入力してacceptすると、ただちにコンパイルが行なわれます。無事、コンパイルが通ると、入力時にあったコードペイン周辺の赤枠が消えます。これで、a BankAccountはbalance: 1000というメッセージを受信できるようになりました。インスペクタのワークスペースで改めて、次式をdo it (cmd-D)してみましょう。インスペクタでbalanceが選択されていれば、その値がnilから1000に変更されるのを確認できるはずです。
[fig.F]インスタンス変数balanceの値が変化したところ
http://squab.no-ip.com:8080/mosaren/uploads/16f.png
さらに続けて、インスタンス変数balanceの値を取り出すメッセージに応答できるように#balanceメソッドを追加します。Smalltalkでは、たとえオブジェクトがbalanceというインスタンス変数を持っていても、改めてアクセス専用のメソッドを定義しないかぎり(インスペクタなどの特殊な手段を除けば)通常の方法で、同インスタンス変数にはアクセスできません。
手順はおおむね、#balance:のときと同じです。ブラウザの上段右端のペイン(メソッドのリスト)に追加され、現在選択状態にあるbalance:をクリックして選択を解除します。すると、balance:の定義前のように、メソッド記述用のテンプレートがコードペインに現われます。マウスカーソルをコードペインの枠内に移動し、選択状態のテンプレートを削除して次のコードを入力し、pretty printでフォーマットを整えた後、accept (cmd-S)してください。
balance
^ balance
メソッド#balanceを起動するメッセージbalanceは、単項メッセージなので、セレクタ(メソッド名)、メッセージパターンはいずれも同じ「balance」です。当然、メッセージにパラメータは伴わないので、パラメータ変数の宣言も必要ありません。コードは、メソッドの返値を明示的にするための記号である“^”(ハット)にインスタンス変数であるbalanceを続けます。1行目のbalance(メッセージパターン、あるいはセレクタ)と2行目のbalance(インスタンス変数)は字面は同じですが別のものを表わしていることに注意してください。
acceptと同時にコンパイルが行なわれ、メソッドリストペインにbalanceが追加されると、その直後からインスペクタでインスペクト中のa BankAccountもメッセージ「balance」に応答できるようになります。
self balance “=> 1000 ”
ところで、今回定義した#balance:や#balanceのように、同名のインスタンス変数にアクセスするためのメソッドは「アクセッサ」と呼ばれ、Smalltalkではaccessingというカテゴリに分類する習わしになっています。そこで、メソッドカテゴリペインの黄ボタンメニューからrename…を選択し、fill in the blankでaccessingと入力してaccept (cmd-S)しておくことにいたしましょう。
[fig.G]as yet unclassifiedカテゴリをrename…
http://squab.no-ip.com:8080/mosaren/uploads/16g.png
[fig.H]accessingカテゴリに収った2つのアクセッサ
http://squab.no-ip.com:8080/mosaren/uploads/16h.png
次回も、BankAccountへのメソッド追加を続けます。
サポートページ:
http://squab.no-ip.com:8080/mosaren/
小池邦人の「Carbon API 徒然草」(2004/10/22)
nibファイルからウィンドウを呼び込む
今回から、メインウィンドウ(CatalogWindow)を操作するための基本ルーチンで使われている自作ルーチンについて順次解説して行きたいと思います。まず最初に、前々回に登場したnewCatalogWindow()ルーチンで使われているcreateMyNibWindow()と、その関連ルーチンの解説からスタートします。
createMyNibWindow()は、nibファイルに登録されているウィンドウオブジェクト(メインウィンドウの雛形)を抽出し適切な初期化を実行します。引数で渡される最初のnameはウィンドウオブジェクトの名称、次のtitleはウィンドウのタイトルです。3つ目の引数のwidには、ウィンドウの種類を認識できるようにするための「識別子」を代入します。メインウィンドウの識別子は’CATA’です。4つ目の引数の*fscは、そのウィンドウに対応したドキュメントファイルの保存場所(FSSpec構造体)を参照するために渡します。ただし、newCatalogWindow()から呼ばれた時には対応するドキュメントは存在しませんので、ここにはNULL(ゼロ)が代入されてきます。ウィンドウが正しく作成されれば、作成されたウィンドウのWindowRefが最後の引数の*wptrに返ります。
short createMyNibWindow( Str255 name,Str255 title,OSType wid,FSSpec *fsc,
WindowRef *wptr )
{
short ret=1;
CFStringRef cref;
IBNibRef nref;
if( ! CreateNibReference( CFSTR( "main" ),&nref ) ) // nibファイルを開く
{
if( cref=CFStringCreateWithPascalString( NULL,name, // オブジェクト名を
CFStringGetSystemEncoding() ) ) // CFStringへ変換
{
if( ! CreateWindowFromNib( nref,cref,wptr ) ) //ウィンドウを抽出
{
if( ret=setupMyWindow( *wptr,title,wid,fsc ) ) // 初期化する
DisposeWindow( *wptr ); // 失敗したら削除
else
moveMyWindowBounds( *wptr ); // 表示位置決定
}
CFRelease( cref ); // オブジェクト名のCFStringを解放
}
DisposeNibReference( nref ); // nibファイルのIBNibRefを解放
}
return( ret );
}
オープンするnibファイルの名称は”main.nib”であり、CreateNibReference()へは拡張子部分を外してから代入します。これでmain.nibファイルへのアクセスが可能となりました。メインウィンドウのオブジェクト名は”CatalogWindow”です。これをCFStringへと変換してからCreateWindowFromNib()へ渡せば、出来上がったウィンドウのWindowRefが返ります。実際のウィンドウ作成のための操作はたったこれだけです。ここまでの処理に問題がなければ、setupMyWindow()でウィンドウの初期化を行なった後、moveMyWindowBounds()でウィンドウの表示位置を決定します。
ウィンドウの初期化で重要な処理は、メインウィンドウに必要なプライベートなメモリ領域(WInfo構造体)をウィンドウのプロパティとして登録し、WindowRef経由でいつでも参照できるようにしておくことです(ウィンドウにくっつけておくこと)。この登録にはWindow ManagerのSetWindowProperty()というAPIを使います。以下が、本アプリで用意したWInfo構造体の内容です。w_prefメンバは画像表示用のビューアウィンドウの方で利用することになりますので別の機会に解説いたします。続くw_optrメンバとw_countメンバには、カタログに登録されているファイル情報(Object構造体のアドレス)とその個数を保存します。ウィンドウ操作に必要なパラメータが増えたら、この構造体に順次メンバを追加していけば良いことになります。
#define MAX_FILE 1000 // カタログに登録できる最大ファイル数
typedef struct {
WindowRef w_pref; // 親ウィンドウのWindowRef
unsigned long w_count; // ObjectPtrの個数
ObjectPtr w_optr[MAX_FILE]; // ObjectPtrのリスト
} WInfo,*WInfoPtr,**WInfoHandle;
以下のsetupMyWindow()ルーチンで、WInfo構造体をウィンドウのプロパティとして登録します。SetWindowProxyFSSpec()は、対応ドキュメントファイルがある場合のみ実行され、ウィンドウタイトルの左側にドキュメントのプロキシアイコンを表示します。実際のプロパティ登録では、WInfo構造体はシステム内部の格納場所に「複製」されますので、自分自身で確保しておいたポインタ(iptr)は不要となります。最後にDisposePtr()で解放することを忘れないでください。
SetWindowProperty()には、そのプロパティの種類を後から判断できるようにシグネイチャとタイプを渡します。つまり何種類もの構造体をプロパティとして登録しておくことも可能なわけです。今回のプロパティ識別には、アプリケーション本体のシグネイチャとドキュメントのファイルタイプを代用しています。こうして保存したプロパティの内容は、GetWindowProperty() APIでいつでも引き出す(読み込む)事が可能です。
short setupMyWindow( WindowRef window,Str255 title,OSType wid,FSSpec *fsc )
{
short ret=1;
WInfoPtr iptr;
if( iptr=(WInfoPtr)NewPtrClear( sizeof( WInfo ) ) ) // WInfo構造体用メモリ確保
{
SetWTitle( window,title ); // ウィンドウのタイトルを設定
SetWRefCon( window,wid ); // ウィンドウの識別子を設定
if( fsc )
SetWindowProxyFSSpec( window,fsc ); //ファイル保存場所を格納
SetWindowModified( window,0 ); // 未編集ウィンドウの印を付ける
ret=setWInfo( window,iptr ); // WInfo構造体をプロパティとして保存
DisposePtr( (Ptr)iptr ); // WInfo構造体用に確保したメモリを解放
}
return( ret );
}
#define MY_SIG 'MosA' // アプリケーションのシグネイチャを代用
#define MY_DOC 'MosD' // ドキュメントのファイルタイプを代用
short setWInfo( WindowRef window,WInfoPtr woptr )
{
short ret=1;
if( IsValidWindowPtr( window ) ) // WindowRefが正常ならプロパティをセット
ret=SetWindowProperty( window,MY_SIG,MY_TAG,sizeof( WInfo ),woptr );
return( ret );
}
続いて、オープンするウィンドウの表示位置をmoveMyWindowBounds()で調整します。メインウィンドウは、スクリーン中心の上方(Alert位置)に表示されるよう、nibファイル側で設定されています。今回は表示回数に応じ、その位置を少し(16ピクセル)右下へ移動させるように工夫してみます。
getWindowContentBounds()でウィンドウ枠のグローバル座標を得て、それにオフセット値をプラスした値をMoveWindow()に渡すことで移動を実現します。本アプリでは、nibファイルから作成するウィンドウは1種類のみですが、別の種類のウィンドウも対応させたい場合には、ケース文で識別子による分岐を実行し、その内部に別の処理を記述すれば良いことになります。
void moveMyWindowBounds( WindowRef window )
{
static long w1_ct=0; // ウィンドウ表示位置のオフセット値カウンター
Rect grt;
short dd;
if( ! FrontWindow() ) // フロントウィンドウが無ければオフセットを初期化
w1_ct=0;
dd=(w1_ct++%5)*16; // オフセット値は5回繰り返すと元に戻る
switch( GetWRefCon( window ) ) // ウィンドウの識別子をチェック
{
case 'CATA': // カタログウィンドウの場合
getWindowContentBounds( window,&grt ); // ウィンドウの現矩形枠を得る
MoveWindow( window,grt.left+dd,grt.top+dd,0 ); //オフセット分ずらす
break;
}
}
void getWindowContentBounds( WindowRef window,Rect *wrt )
{
RgnHandle rgn;
rgn=NewRgn();
GetWindowRegion( window,kWindowContentRgn,rgn ); // ウィンドウのContentRgn
GetRegionBounds( rgn,wrt ); // その矩形枠を得る
DisposeRgn( rgn );
}
最後に、createMyNibWindow()で得られたWindowRefをTransitionWindow()かShowWindow()に渡せばメインウィンドウがスクリーンの指定位置にオープンします。ちなみに、この表示作業はnewCatalogWindow()やopenCatalogWindow()側で行います。
次回は、newCatalogWindow()で使われているsetupCatalogWindow()と、その関連ルーチンを調べてみることにします。メインウィンドウに実装するイベントハンドラの解説が中心で、アバウトダイアログで解説した内容の応用編となります。
つづく
「Behind the WebObjects」 第30回 田畑 英和
今回は「WOUnitTest」解説の続きです。前回はWOUnitTestのセットアップ方法と基本的な使い方をご紹介しましたが、その続編としてテストケースの作成方法について説明いたします。
テストの概要
WOUnitTestでは、テスト用のコード(テストケース)を使って目的のコードをテストします。つまりテスト対象のコード(クラス)が提供するAPIを用いたプログラミングをおこない、実際にプログラムを実行して動作をテストするわけですが、これはWOUnitTestのベースとなっているJUnitでのテスト方法と同じです。実際にプログラムを実行させてテストするわけですから、テストケースと同じ使い方をするのであれば、正常に動作することが期待できるわけです。そのためにはまずテストケースを作成しなくてはなりませんが、さっそく簡単な例を用いて作成方法を紹介していきます。
テスト仕様
例えばクラス”Sample”に実装された以下のようなメソッドをテストするとします。このメソッドは2つの文字列(ユーザ名とパスワード)を引数で指定し、ログイン認証をおこなうメソッドとします。単純な例とするために登録済みのユーザは1人だけとします。
・テスト対象のメソッド
/**
* ログイン認証、大文字小文字を区別する
* @param name ユーザ名
* @param password パスワード
* @return 認証結果
*/
public static boolean login(String name, String password)
・登録済みのユーザ
name = admin
password = wo
この場合nameが”admin”、passwordが”wo”の場合のみtrueが返ればよいことになりますし、逆にそれ以外のパターンではfalseが返る必要があります。つまり、正常な入力がおこなわれた場合に認証がおこなわれることをテストするだけでなく、不正な入力がおこなわれたときには認証がおこなわれないこともテストする必要があります。
ですのでテストデータとしては、正常な場合と不正な場合をそれぞれ用意する必要があります。この場合、正常な場合は登録済みのユーザということになりますので、あとは不正なデータを用意すればよいことになります。例えば次のようなテストデータを用意したとします。
・テストデータ(name/password)
正常なパターン:admin/wo
不正なパターン:wo/admin, admin/admin, Admin/wo
このようなテストデータを用いて実際にlogin()メソッドでログイン認証をおこなうテストケースを作成し、正常なパターンではtrueが、不正なパターンではfalseが返ればこのメソッドが正しく動作することがテストできたことになります。
テストケースの作成
(1)フレームワークの追加
まずフレームワーク”WOUnitTest.framework”をプロジェクトに追加してください。このフレームワークのインストール方法については前回解説しました。フレームワークを追加することにより、アプリケーションにUnitTestの機能が追加されます。
(2)テストケースの作成
次にテストケースのクラスを作成します。テストケースクラスはWOUnitTestが提供するWOUTTestCaseを親クラスとして指定し、クラス名は”TestCase”あるいは”Test”でおわるように命名してください。ここでは”SampleTestCase”とします。
テストケースを簡単に作成できるよう、WOUnitTestのインストール時にテストケースのテンプレートもインストールされています。Xcodeで新規ファイル作成時にWebObjectsグループから「WOUTTestCase class」が選択できるようになっていますので、こちらを利用すると自動的にWOUnitTestを親クラスとするテストケースクラスが生成されます。
自動生成されたクラスには前処理用のsetUp()、後処理用のtearDown()、空のテストメソッドtest()などがあらかじめ用意されています。
クラスが作成できたら、今度はテスト用のメソッドを追加します。このときメソッド名は”test”で始まるようにしてください。今回は”testLogin()”とします。例えば次のようなテストケースクラスを作成します。
・テストケースクラスサンプル
public class SampleTestCase extends WOUTTestCase {
public void testLogin() {
assertTrue(Sample.login("admin", "wo"));
assertFalse(Sample.login("wo", "admin"));
assertFalse(Sample.login("admin", "admin"));
assertFalse(Sample.login("Admin", "wo"));
}
}
※assertTrue/assertFalse
それぞれ引数にtrue/falseが指定されたかを評価するJUnitのメソッド
(3)テストケースの実行
テストケースが作成できたら、アプリケーションをビルド&実行してください。login()の実装については省略しますが、ログイン認証をおこなう適切なコードが実装されているものとします。アプリケーションが起動したら以下のURLにアクセスしてください。このURLのページはDirectActionを利用することによりWOUnitTestが提供しています。
・WOUnitTestのURL
/cgi-bin/WebObjects/[application name].woa/wa/ut
ここまでくれば後の手順は前回説明したWOUnitTestTestと同様です。ただし今回はテストケースのクラスは1つしか用意していませんので画面左側のTest Case一覧には”SampleTestCase”のみが表示されているはずです。
あとは「Run All」をクリックすればSampleTestCaseのtestLoginが自動的に実行されます。もしテストに失敗した場合はlogin()メソッドの実装にバグがあるということですので、テストが成功するようにlogin()を修正する必要があります。
まとめ
今回はテストケースの作成方法を紹介することが目的でしたので、単純な例を示しましたが、実際のテストはさらに複雑になるでしょう。login()の仕様もpasswordがnullの場合は認証を許可しないといった仕様も考えられますし、仕様が複雑になればその分テストパターンも増えるでしょう。さらにテスト対象のクラス/メソッドも一般には複数ありますから、それらに対応するテストケースも必要になっていきます。
効果的なテストケースの書き方などはテスティングに関する文献を参照してみてください。Web上でも様々な情報が得られるでしょう。
ところでSampleTestCaseはWOUTTestCaseを親クラスに指定しましたが、実はまだWOUTTestCase固有の機能を使ったテストケースではありませんでした。
WOUTTestCaseはJUnitをベースにしていますが、今回はまだJUnitの機能を利用しているだけです。WOUTTestCaseではカスタムEOをテストするのに便利な機能が用意されていますので次回はそちらを紹介したいと思います。
ニュース・解説
今週の解説担当:新居雅行
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┃Core Dataの概要が公開、さらに開発者にはTigerプレビュー版をリリース
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ADCのページに次期Mac OS Xとなる「Tiger」についての「Developer Overview」というページが追加された。併せて、「Tiger Early Start Kit for Developers」についても告知された。2005年前半リリース予定のMac OS X v10.4“Tiger”に向けて、開発者が対応アプリケーションなどを開発しやすくするため、情報公開を早めたと言えるだろう。
Tigerについては、2004年6月末のWWDC 2004である程度公開され、WWDC 2004では内容はまだ機密ながら、開発者に対して新機能のさまざまな情報が公開されている。その後、Sneak Previewとして、機能や画面が公開されていたが、たとえばiChatでのビデオ会議などといったエンドユーザ向けの訴求点が中心ではあった。「Developer Overview」のページでは、開発者がフォーカスしたいポイントがまとめられている点で興味深いと言えるだろう。なお、Dashboardなどの新しい素材に関するものや、Spotlightのように既存アプリケーションなどにも影響のある側面などいろいろとあるが、従来になかった情報として、Core Dataについての解説がある。
Core Dataの解説部分を要約すると次のようなことだ。PantherではCocoa Bindingsが組み込まれて、GUIのコンポーネントとモデルのバインドが可能になっている。TigerではCore Dataが搭載されて、自動的なUndo/Redo、ユーザインタフェースコンポーネントと同期のさらに強化、データの一貫性保持、読み書きスピードの高速化などが達成される。Core Dataに基づき、開発者がターゲットとしているデータオブジェクトの記述を行えば、データのメモリ内部あるいはハードディスク内部でのメンテナンスといった面倒な仕事は多くの部分がCore Dataがまかなってくれる。開発者はアプリケーションの機能を組み込むことに集中できる。つまり、Core Dataはモデル駆動型のオブジェクトのグラフ化および永続化を行うフレームワークである。また、ストレージモデルとしては、XMLファイル、バイナリファイル、そしてSQLiteを利用できる。
「Tiger Early Start Kit for Developers」は単独で発売されるのではなく、ADCのSelect以上のメンバに対して配布される。つまり、未公開ソフトウエアの試用や評価のためのシードプログラムに含まれる。まだADC会員ではない人は入会をすればいいわけだが、既存のSelect以上の会員に対しても配布されるようだ。TigerとXcode 2.0のプレリリース版はもちろん、最新版のドキュメントや、WWDC 2004でのTiger関連セッションの様子を収めたDVDも含まれる。また、Appleのサポートエンジニアによるサポートや、ハードウエアのディスカウントということも項目として上がっているが、これはSelectメンバの条項によるものと思われる。サイトではこのStart Kitはすでに入手可能となっている。次期OSのTigerのリリースに向けて、早期にアプリケーションの対応を促し、さらには開発者をより多く引き込むという意図があると考えられる。
Mac OS X v10.4 Tiger: Developer Overview
http://developer.apple.com/macosx/tiger/index.html
Tiger Early Start Kit for Developers
http://developer.apple.com/macosx/tiger/tigerkit.html
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┃QuickTimeでのスレッドセーフに開発するための知識
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Technical Notesに、QuickTimeでのスレッドセーフなプログラムを作成するための知識が公開された。Mac OS X v10.3になって、QuickTimeのAPIがスレッドセーフとなったが、それまではスレッドセーフでなかった。バックエンドで何かするということはあまりないために表面化はしなかったが、今後はマルチタスク環境で、他のプロセスとの共存をより意識する必要があるだろう。なお、スレッドセーフにはなっても、同一のメモリ上のQuickTimeオブジェクトを複数のスレッドからのアクセスはできなくなっている。ソースコードの例を示すなどかなり長いリストになっているが、Mac OS X環境でQuickTimeを利用している開発者は一読しておく必要があるだろう。
Technical Notes: Thread-safe programming in QuickTime
http://developer.apple.com/technotes/tn/tn2125.html
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┃NSViewで拡大縮小率を得る方法
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Technical Q&Aに、CocoaのNSViewにおいて、現在の拡大率などの値を取り出す方法が紹介されている。NSViewではスケールを設定するメソッドがあるが、これらを利用し、さらにObjective-Cのカテゴリを利用してNSViewを拡張し、拡張したメソッドを通じて拡大や縮小を行うことで、後から拡大縮小率を簡単に得られるようにするという方法がソース付きで紹介されている。
Technical Q&A:Finding an NSViews current magnification
http://developer.apple.com/qa/qa2004/qa1346.html
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┃VRAMサイズを求める方法
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
VRAMのサイズを求める方法がTechnical Q&Aに公開された。Core GraphicsとIOKitを使う方法がある。ソースコードが掲載されているので、そのまま使えるだろう。
Technical Q&A:How do I determine how much VRAM is available on my video card?
http://developer.apple.com/qa/qa2004/qa1168.html
MOSAからのお知らせと編集後記は割愛します
Apple、Mac OSは米国アップルコンピュータ社の登録商標です。またそのほかの各製品名等はそれぞれ各社の商標ならびに登録商標です。
このメールの再配信、および掲載された記事の無断転載を禁じます。
http://www.mosa.gr.jp/
Copyright (C)2004-2006 MOSA. All rights reserved.