Objective-C は、Apple が Mac OS X および iPhone の開発に使用しているため、広く使用されています。Objective-C 言語のお気に入りの「隠れた」機能は何ですか?
- 回答ごとに 1 つの機能。
- ドキュメントへのリンクだけでなく、機能の例と簡単な説明を提供してください。
- 最初の行としてタイトルを使用してフィーチャにラベルを付けます。
Objective-C は、Apple が Mac OS X および iPhone の開発に使用しているため、広く使用されています。Objective-C 言語のお気に入りの「隠れた」機能は何ですか?
基本的に、実行時にメソッドの 1 つの実装を別の実装に交換できます。
巧妙な使用例の 1 つは、共有リソースの遅延ロードです。通常は、ロックを取得し、必要に応じsharedFoo
て を作成し、foo
アドレスを取得してロックを解放し、 を返すことでメソッドを実装しfoo
ます。これにより、foo
が 1 回だけ作成されるようになりますが、その後のすべてのアクセスでは、不要になったロックで時間が浪費されます。
メソッドのスウィズリングを使用すると、以前と同じことができますが、foo
が作成されたら、スウィズリングを使用して の最初の実装を、チェックを行わず、作成されたことがわかっている をsharedFoo
返すだけの 2 番目の実装と交換します。foo
もちろん、メソッドの入れ替わりはトラブルに巻き込まれる可能性があり、上記の例が悪い考えである状況もあるかもしれませんが、ちょっと...それが隠された機能である理由です.
Objective-C では、クラスがアプリケーション内の別のクラスを完全に置き換えることができます。置換クラスは、ターゲット クラスの「ポーズ」と呼ばれます。ターゲット クラスに送信されたすべてのメッセージは、代わりにポージング クラスによって受信されます。クラスが課すことができるいくつかの制限があります。
ポージングは、カテゴリと同様に、既存のクラスをグローバルに拡張できます。ポージングでは、カテゴリにない 2 つの機能が許可されます。
例:
@interface CustomNSApplication : NSApplication
@end
@implementation CustomNSApplication
- (void) setMainMenu: (NSMenu*) menu
{
// do something with menu
}
@end
class_poseAs ([CustomNSApplication class], [NSApplication class]);
これにより、setMainMenu から NSApplication へのすべての呼び出しがインターセプトされます。
オブジェクトの転送/メソッドがありません
メソッドのないメッセージがオブジェクトに送信されると、ランタイム システムは、あきらめる前に呼び出しを処理する別の機会をオブジェクトに与えます。オブジェクトが -forward:: メソッドをサポートしている場合、ランタイムはこのメソッドを呼び出し、未処理の呼び出しに関する情報を渡します。転送された呼び出しからの戻り値は、メソッドの元の呼び出し元に伝播されます。
-(retval_t)forward:(SEL)sel :(arglist_t)args {
if ([myDelegate respondsTo:sel])
return [myDelegate performv:sel :args]
else
return [super forward:sel :args];
}
Objective-C Pocket Reference の内容
これは非常に強力で、さまざまな DSL やレールなどのために Ruby コミュニティで頻繁に使用されています。Objective-C と Ruby の両方に影響を与えた Smalltalk で生まれました。
オブジェクトのすべての動作をオーバーライドする必要がありますか? 1 行のコードでアクティブなオブジェクトのクラスを実際に変更できます。
obj->isa = [NewClass class];
これは、そのオブジェクトのメソッド呼び出しを受け取るクラスのみを変更します。メモリ内のオブジェクトのレイアウトは変更されません。したがって、これは、同じ ivar (または他のサブセットを持つクラス) を持つクラスのセットがあり、それらを切り替えたい場合にのみ本当に役立ちます。
私が書いたコードの 1 つでは、これを遅延読み込みに使用しています。これは、 class のオブジェクトを割り当て、A
いくつかの重要な ivar (この場合は主にレコード番号) を埋め、isa
ポインターを に切り替えるLazyA
。release
andのような非常に小さなセット以外のメソッドretain
が呼び出されると、LazyA
ディスクからすべてのデータがロードされ、ivar への入力が完了し、isa
ポインターが に戻りA
、呼び出しが実際のクラスに転送されます。
#include <Foundation/Debug.h>
そのヘッダー ファイル内のメモリ リーク、時期尚早の解放などを追跡するための多くのツール。
カテゴリー
カテゴリを使用すると、サブクラス化せずに組み込みクラスにメソッドを追加できます。完全な参照。
NSString や NSData など、一般的に使用されるクラスに便利なメソッドを追加すると便利です。
Objective-Cランタイムリファレンス
Objective-CのシンタックスシュガーがObject-Cランタイムである通常のC関数呼び出しに変換されることを忘れがちです。ランタイムで実際に何かを調べて使用する必要はないでしょう。そのため、これを「隠し機能」と見なします。
ランタイムシステムを使用する方法を説明しましょう。
誰かがサードパーティによって使用される外部フレームワークAPIを設計しているとしましょう。そして、誰かがデータのパケットを抽象的に表すフレームワークでクラスを設計することを、私たちはそれと呼びますMLAbstractDataPacket
。これで、フレームワークでサブクラスにリンクしMLAbstractDataPacket
、サブクラスデータパケットを定義するのはアプリケーション次第です。すべてのサブクラスはメソッドをオーバーライドする必要があります+(BOOL)isMyKindOfDataPacket:(NSData *)data
。
その情報を念頭に置いて...
MLAbstractDataPacket
の形式で提供されるデータのパケットに対して正しい初期化されたクラスを返す便利なメソッドが提供されていると便利です+(id)initWithDataPacket:(NSData *)data
。
ここでの問題は1つだけです。スーパークラスは、そのサブクラスについては知りません。したがって、ここでは、ランタイムメソッドobjc_getClassList()
を一緒に使用しobjc_getSuperclass()
て、MLAbstractDataPacketのサブクラスであるクラスを見つけることができます。サブクラスのリストを取得したら、サブクラス+isMyKindOfDataPacket:
が見つかるか見つからなくなるまで、それぞれを試すことができます。
これに関するリファレンス情報は、http://developer.apple.com/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.htmlにあります。
[myArray writeToFile:myPath atomically:YES]
私は、すべての引数にラベルがある のような冗長なメソッド命名が好きです。