ココアの奥深く

この記事では、Cocoaとその基本原則についてもう少し説明しようとします。 私はすぐに材料が包括的なものではないことを言うので、 ここで材料を学んでいます

Xcodeを開き、新しいCocoaアプリケーションを作成し、DotViewという名前を付けます。 私たちのプログラムは何をしますか? 彼女はNSViewコンポーネントにポイントを描画します。 NSViewとは何ですか? これは、Cocoaグラフィカルウィジェットの基本クラスです。したがって、独自のウィジェットを作成する場合は、おそらくNSViewの後継になります。

次に、プロジェクトに新しいクラスを追加します。 File => New Fileを開き、開いたウィンドウで「Objective-C NSViewサブクラス」を選択し、「次へ」をクリックして、名前としてDotViewを設定します。
クラスDotViewを作成します
それでは、DotView.mファイルの内容を見てみましょう。 ウィザードには、2つの関数が既に追加されています。-(id)initWithFrame:(NSRect)frameおよび-(void)drawRect:(NSRect)rect。 最初の関数はDotViewタイプの新しいオブジェクトを作成するときに呼び出され、2番目の関数はコンポーネントを再描画する必要があるたびに呼び出されるため、そこにレンダリングコマンドを配置するのが論理的です。

drawRect関数に数行を追加します。
NSRect境界= [自己境界];
[[NSColor whiteColor] set];
NSRectFill(境界);

最初のコマンドは、コンポーネントの現在の寸法を取得します。 NSRectは通常のC構造です。
2番目のコマンドでは、最初にNSColorオブジェクトにwhiteColorメッセージを送信します。その結果、白色を返します。次に、受信した色にsetメッセージを送信します。
3番目のコマンドは、パラメーターとして渡された領域をCurrent Graphics Contentsで設定された色で塗りつぶす関数呼び出しです。 この例から、Cocoaはオブジェクトのコレクションであるだけでなく、頻繁に使用される便利な関数の集まりも持っていることが明らかです。

さて、ここでポイントを描画するコードを作成します。
ポイントとなる長方形の領域を記述する構造を作成します
NSRect dotRect = NSMakeRect(50、50、100、100)

この行はすでに明確になっているはずです
[[NSColor blueColor] set];

新しいベジエ曲線を作成します。これは、指定された領域で楕円になり(この場合は円になります)、すぐに作成された曲線に塗りつぶしメッセージを送信します。これにより、曲線が描画され、現在の色で塗りつぶされます。
[[NSBezierPath bezierPathWithOvalInRect:dotRect] fill];

最後に、drawRect関数は次のようになります。
-(void)drawRect:(NSRect)rect {
NSRect境界= [自己境界];
[[NSColor whiteColor] set];
NSRectFill(境界);
NSRect dotRect = NSMakeRect(50、50、100、100);
[[NSColor blueColor] set];
[[NSBezierPath bezierPathWithOvalInRect:dotRect] fill];
}


ファイルを保存し、MainMenu.nibをクリックしてInterface Builderに入ります。
CustomViewコンポーネントをウィンドウに配置し、ストレッチして、ウィンドウの境界(インスペクターパネルのサイズタブ)にスナップします。 [クラス]コンボボックスの[インスペクター]パネルの[ID]タブで、[DotView]を選択します。コンポーネントはカスタムビューではなく、DotViewになりました。 保存し、Xcodeに戻り、ビルドして実行し、結果を取得します。


アプリケーションの機能を少し増やしましょう。 DotView.hファイルを開き、2つのフィールドNSPoint centerをDotViewクラスに追加します-ポイントの中心、フロート半径-ポイントの半径:
インターフェース DotView:NSView {
NSPointセンター;
フロート半径;
}

ここで、クラスのインスタンスを作成するときに、これらの変数を初期化する必要があるため、initWithFrame関数に初期値を追加します。
-(id)initWithFrame:(NSRect)フレーム{
self = [super initWithFrame:frame];
if(self){
center.x = center.y = 100.0;
半径= 50;
}
自己を返す;
}

基本的に、ポイントレンダリング関数を少しやり直す必要があります。つまり、境界線を作成するための行を変更します。
NSRect dotRect = NSMakeRect(center.x-radius、center.y-radius、2 *半径、2 *半径);


マウスボタンをクリックすると、ポイントがカーソルのあるポイントに移動するようになります。 これを行うには、関数-(void)mouseDown:(NSEvent *)イベントを定義します。 この関数は、コンポーネントでマウスボタンがクリックされるたびに呼び出されます。 event-イベントに関するすべての必要な情報が保存される変数。
関数内で、次のように記述します。
クリックしたポイントの座標を取得します
NSPointポイント= [イベントlocationInWindow];

ここで、ウィジェットのクリックしたポイントの座標に対応する座標にポイントの中心を割り当てます
center = [self convertPoint:ポイントfromView:nil];

そして、変更を有効にするためにウィジェットを再描画する必要があります。 ただし、drawRect関数を直接呼び出す代わりに、ウィジェットに再描画するように指示します。
[self setNeedsDisplay:YES];

ここで関数が終了します。

より面白くするために、クリックだけでなくドラッグによってポイントの位置を変更できるように、関数-(void)mouseDragged:(NSEvent *)イベントを定義します。
-(void)mouseDragged:(NSEvent *)イベント{
[self mouseDown:event];
}

現時点では、DotViewクラスは次のとおりです。

結果を保存して起動し、楽しんでいます。

ターゲット/アクション


Cocoaの各ウィジェットには、ターゲットとアクションがあります。 ターゲットは、ウィジェットに事前に決定された何かが発生したときにメッセージが送信されるオブジェクトです。 たとえば、スライダーの位置を変更すると、メッセージがターゲットに送信されます。 アクションは、送信する実際のメッセージです。 このメッセージには常に1つの引数があります。

ここで、プログラムにポイントのサイズを変更する機能を追加する必要があります。 これを行うには、クラスで関数を定義します-(void)changeSize:(id)sender 送信者の引数は、このメッセージを送信したウィジェットです。 関数は次のようになります。
-(void)changeSize:(id)sender {
radius = [sender floatValue];
[self setNeedsDisplay:YES];
}

このメソッドはNSViewクラスに属していないため、その定義をDotView.hに記述する必要があります。 このメソッドを表示するにはIBが必要です。したがって、戻り値の型としてIBActionを記述する必要があります。 DotView.hのコンテンツは次のようになります。
#import <Cocoa / Cocoa.h>

インターフェース DotView:NSView {
NSPointセンター;
フロート半径;
}
-(IBAction)changeSize:(id)送信者。
終わり

すべてを保存してIBに移動します。 スライダーをフォームに追加し、DotViewコンポーネントからAction changeSizeとして設定します(スライダーで押したコントロールでマウスをDotViewにドラッグし、ドロップダウンリストでマウスボタンを放した後、changeSize:を選択します)。 また、スライダーのインスペクターパネルの[属性]タブで、[連続]ボックスをオンにして、マウスボタンを放した後ではなく、値が変更されたときにメッセージを送信します。
保存し、Xcodeにアクセスし、コンパイルし、プロジェクトを実行して、目的のもの(ポイントの移動、サイズ変更)を取得します。


次に、実際に何が起こったのかを把握する必要があります。 スライダーには、idターゲットとSELアクションの2つのフィールドがあります。 IBを使用してスライダーとDotViewを接続すると、IBはターゲットフィールドをDotViewオブジェクトに、SELをセレクター (changeSize :)に設定します。 IBにより作業が簡素化され、特別なものを表さないコードを大量に記述する必要がなくなりました(ただし、CocoaアプリケーションはIBの助けを借りずに自分で作成できます)。

メモリ管理


NSObjectの子孫である各オブジェクトには、参照カウントフィールドがあります。 このフィールドはどういう意味ですか? このフィールドは、これに関心のあるオブジェクトの数を示します。 オブジェクトが作成されるとき、その参照カウントは1です。オブジェクトに関心がある場合、保持メッセージを送信する必要があり、参照カウントは1増加します。オブジェクトに関心がなくなった場合、参照を減らすリリースメッセージを送信する必要があります1カウントし、参照カウントがゼロになったかどうかを確認しますが、deallocメッセージをオブジェクトに送信します。

Cocoaでは、オブジェクトを作成した人がそれを削除することが認められています。 オブジェクトが必要な場合は、メッセージの保持を送信しますが、メッセージリリースの送信を忘れないでください。

アプリケーションを改善します。 これで、ドットの色が変わります。 これを行うには、新しいインスタンス変数NSColor * colorをDotView.hファイルに追加します。 また、新しいメソッドをクラスに追加します-(IBAction)changeColor:(id)sender;、ファイルを保存し、DotView.mに戻ります。

次にchangeColor関数について説明します。
-(void)changeColor:(id)sender {
NSColor * newColor = [送信者の色];
[self setColor:newColor];
}

新しい色では何もしていないことに注意してください。送信側から現在の色へのポインタを取得し、パラメータとしてsetColor関数に渡します。

次に、setColor関数について説明します。
-(void)setColor:(NSColor *)newColor {
if(newColor!= color){
[カラーリリース];
color = [newColor retain];
[self setNeedsDisplay:YES];
}
}

Cocoaでメモリを管理するという考えは、この方法ではっきりと見えます。 リリースメッセージを古い値に送信し、新しい値を保持します。 setColor関数をヘッダーファイルに追加しないようにするには、changeColor:よりも前に記述してください。

また、色を初期化することを忘れないでください。 initWithFrame関数に次の行を追加します。
color = [[NSColor blueColor] retain];


次に、dealloc関数について説明する必要があります。
-(void)dealloc {
[カラーリリース];
[super dealloc];
}

カラー変数はdeallocではなくリリースされるので、 誰かが変数に興味を持っている可能性があります。 また、dellocスーパークラスにメッセージを送信する必要があります。

次に、関数drawRectを調整する必要があります。 代わりに
[[NSColor blueColor] set];

書きます
[色セット];

すべてのファイルを保存します。

次に、コンポーネントをフォームに配置する必要があります。これにより、色を変更します。 これを行うには、IBに移動し、Color Wellコンポーネント(色を選択するための標準コンポーネント)をフォームに転送し、アクションとしてDotViewからchangeColor:を設定します。

保存して、Xcodeに移動し、起動してお楽しみください:スライダーを動かします-ポイントのサイズが変わり、色を変えます-色が変わります。

次のパートでは、CocoaでのModel-View-Controller、Key-Value Coding、およびKey-Value Observingについて説明します。

誰が非常に興味があり、宿題として、ポイントがコンポーネントを超えないようにしてください。

PS:もしあれば、プロジェクトファイルはここにあります

Source: https://habr.com/ru/post/J26049/


All Articles