2

すでに割り当てられているオブジェクトがある場合、実行object.classすると nil 以外の値が返されます。ここまでは順調ですね。ただし、オブジェクトがまだ割り当てられていない場合、アクセスするとobject.classが返されますnil

そのタイプに基づいて動的にオブジェクトを割り当てたいので、例えば:

@property NSArray *myArray;
...

// myArray is nil so far

self.myArray = [_myArray.class new];

_myArray.classただし、 nil を返すため、これを行うことはできません。では、nil インスタンスのクラス タイプをどのように判断すればよいでしょうか。

更新: 実際には可能です。以下の私の答えをチェックしてください。

4

5 に答える 5

4

インスタンスにはクラスがないため、インスタンスのクラスを特定することはできませnilん。文字通り、変数の型から派生した任意の型にすることができます。たとえば、次のNSMutableArrayものと完全に互換性がありNSArrayます。

NSArray *myArray = [NSArray new]; // OK
NSArray *myArray = [NSMutableArray new]; // Also OK

異なるサブクラスの実行時の機能は大きく異なる可能性があるため、必要なオブジェクトの種類を決定するのは常にプログラム次第です。

于 2013-03-23T15:01:32.963 に答える
3

Objective-Cはダックタイピング言語です。これは、実行できることと実行できないことがいくつかあることを意味します。実行できないことの1つは、変数の型への参照を静的に取得することです。

具体的には、あなたの表現では:

[_myArray.class new]

まず、_myArray.classが評価され、次に結果がnewメッセージに送信されます。_myArraynil始まるので、も戻ります。また、 _myArray.classreturnsにメッセージを送信するため(またはreturn型が持つゼロに最も近い表現)、メッセージも返されます。これが機能しない理由です。nilnewnilnilnil

あなたはC#のような強く型付けされた言語から来ていると思います。現在実行しているのは、と同等です。これは、値が割り当てられていないため、コンパイルも例外もスローしないため(クラスフィールドかローカル変数かによって異なります)、Foo foo = (Foo)Activator.CreateInstance(foo.GetType())必ず失敗します。foo.GetType()Objective-Cでは、コンパイルされますが、機能しません。必要なのはですがActivator.CreateInstance(typeof(Foo))、ここでもハードコーディングされていることに注意してFooください。したがって、を作成するだけでもかまいませんnew Foo()

あなたは、コンパイラがオブジェクトの「タイプを知っている」と言います。これは正確には真実ではありません。まず、NSArrayクラスクラスターNSMutableArrayのルートクラスです。NSArrayこれは、両方が抽象であり、サブクラスのインスタンス[NSArray alloc][NSMutableArray alloc]返すことを意味します(NSCFArray前回チェックしたとき、そしておそらく他の何か。見たことを思い出します_NSArrayM)。たぶん[NSArray new]うまくいくかもしれませんが、それはあなたに明白なことを与えていませんNSArray

第二に、型安全性は強制されません。このコードを考えてみましょう:

id foo = @"foo";
NSArray* bar = foo; // no warning!

したがって、コンパイラはそれをであると考えていても、bar実際NSArrayにはNSStringです。コードをプラグインした場合:

id foo = @"foo";
NSArray* bar = foo; // no warning!
NSArray* baz = [bar.class new];

bazNSStringもです。のランタイムクラスを要求するのでbar、コンパイラは操作とは何の関係もありません。

そして、まさにその種の振る舞いのために、あなたはおそらくあなたが知っているクラスであなたのオブジェクトをインスタンス化するべきです[NSArray new]_myArraynil

于 2013-03-23T15:06:34.683 に答える
1

プロパティを初期化する必要があります。そうしないと nil になり、nil オブジェクトにメッセージを送信すると nil が返されるため、最初に次のように配列を初期化する必要があります。_array = [[NSArray alloc] init];

于 2013-03-23T15:03:51.757 に答える
0

したがって、これが可能かどうか疑問に思っている人にとっては、次のとおりです。

objc_property_t property = class_getProperty(self.class, "myArray");
const char * const attrString = property_getAttributes(property);
const char *typeString = attrString + 1;
const char *next = NSGetSizeAndAlignment(typeString, NULL, NULL);
const char *className = typeString + 2;
next = strchr(className, '"');
size_t classNameLength = next - className;
char trimmedName[classNameLength + 1];

strncpy(trimmedName, className, classNameLength);
trimmedName[classNameLength] = '\0';
Class objectClass = objc_getClass(trimmedName);

NSLog(@"%@", objectClass);

出力:

NSアレイ

extobjcの助けを借りて完了。

于 2013-03-23T15:51:24.450 に答える
-1

Nil にはクラス型がありません

Objective-C では、インスタンス変数の実際のクラスは実行時にのみ決定されます。したがって、nil オブジェクトのクラスを知ることはできません。

次のことだけを行う必要があるため、これはあなたの状況では問題になりません。

NSArray *myArray = [NSArray new];

または

NSArray *myArray = [[NSArray alloc] init];

Objective-C では、ほとんどの決定は実行時に延期されます

(できるだけ)

Objective-C はランタイム指向の言語です。つまり、可能な場合は、実際に何が実行されるかについての決定を、コンパイルおよびリンク時から実際にランタイムで実行するときまで延期します。

これにより、必要に応じてメッセージを適切なオブジェクトにリダイレクトしたり、メソッドの実装を意図的に交換したりできるなど、柔軟性が大幅に向上します。

これには、オブジェクトをイントロスペクトして、オブジェクトが何に応答し、何に応答しないかを確認し、メソッドを適切にディスパッチできるランタイムを使用する必要があります。これを C のような言語と比較すると、C では main() メソッドから開始し、そこからロジックに従ってコードを記述しながら関数を実行するトップダウン設計になります。AC 構造体は、関数を実行する要求を他のターゲットに転送できません。

出典: Objective-C ランタイムを理解する

于 2013-03-23T15:04:44.673 に答える