7

あらゆる種類の変数、プリミティブ、およびオブジェクトを取る関数または NSLog() のようなディレクティブを作成したいと考えています。その機能では、それらを区別したいと思います。

私はそれがオブジェクトに対してどのように機能するかを知っています:

- (void)test:(id)object {
    if ([object isKindOfClass:[NSString class]])
        ...

しかし、オブジェクトを構造体や整数や浮動小数点数と区別するにはどうすればよいですか。何かのようなもの:

"isKindOfStruct:CGRect" or "isInt" 

例えば?

これは可能ですか?すべてを NSLog(@"...", objects, ints, structs) に送信できるので、可能だと思いましたか?

助けてくれてありがとう!

編集

私の最終的な目標は、ある種のポリモーフィズムを実装することです。

私は自分の関数を呼び出すことができるようにしたい:

MY_FUNCTION(int)
MY_FUNCTION(CGRect)
MY_FUNCTION(NSString *)
...

or [self MYFUNCTION:int]...

そしてMY_FUNCTIONで

-(void)MYFUNCTION:(???)value {
    if ([value isKindOf:int])
        ...
    else if ([value isKindOf:CGRect])
        ...
    else if ([value isKindOfClass:[NSString class]])
        ...
 }

isKindOf が存在せず、プリミティブでそのようなメソッドを実行することさえできないことを私は知っています。「???」についてもよくわかりません。関数ヘッダーの「値」のジェネリック型。

それは可能ですか?

4

6 に答える 6

8
#define IS_OBJECT(T) _Generic( (T), id: YES, default: NO)

NSRect    a = (NSRect){1,2,3,4};
NSString* b = @"whatAmI?";
NSInteger c = 9;

NSLog(@"%@", IS_OBJECT(a)?@"YES":@"NO"); // -> NO
NSLog(@"%@", IS_OBJECT(b)?@"YES":@"NO"); // -> YES
NSLog(@"%@", IS_OBJECT(c)?@"YES":@"NO"); // -> NO

また、Vincent Gable のThe Most Useful Objective-C Code I've Ever Writtenをチェックして、指定さ@encode()れた型を説明する文字列を返すコンパイラ ディレクティブを使用する非常に便利なものを確認してください..."

LOG_EXPR(x) は、x の型に関係なく、フォーマット文字列 (および、NSString と同じ方法で C 文字列を出力することによる関連するクラッシュ) を気にすることなく、x を出力するマクロです。Mac OS X および iOS で動作します。

于 2013-07-07T03:56:47.350 に答える
3

次のような関数NSLog()は、最初のパラメーターとして渡す書式文字列から、パラメーター リストに期待される型を伝えることができます。したがって、パラメーターをクエリしてその型を把握するのではなく、書式文字列に基づいて期待する型を把握し、それに応じてパラメーターを解釈します。

于 2012-04-06T15:25:44.487 に答える
2

C 構造体またはプリミティブを type のパラメーターとして渡すことはできませんid。そのためには、プリミティブを NSNumber または NSValue オブジェクトでラップする必要があります。

例えば

[self test: [NSNumber numberWithInt: 3.0]];

idObjective-C オブジェクトへのポインタとして定義されます。

于 2012-04-06T15:31:55.730 に答える
2

@alex gray answer は機能しませんでした (または、少なくとも iOS SDK 8.0 では機能しませんでした)。@ deepax11 の回答を使用できますが、この「魔法のマクロ」がどのように機能するかを指摘したいと思います。システムから提供される型エンコーディングに依存します。Appleのドキュメントによると:

ランタイム システムを支援するために、コンパイラは各メソッドの戻り値と引数の型を文字列にエンコードし、その文字列をメソッド セレクタに関連付けます。使用するコーディング スキームは、他のコンテキストでも役立つため、@encode() コンパイラ ディレクティブで公開されています。型指定が与えられると、@encode() はその型をエンコードする文字列を返します。型は、int、ポインター、タグ付き構造体または共用体、またはクラス名などの基本型にすることができます。実際には、C sizeof() 演算子の引数として使用できる任意の型です。

マクロを分解するには、最初に変数「typeOf」を取得し、その型で @encode() を呼び出し、最後に、返された値をエンコーディング テーブルの「オブジェクト」および「クラス」型と比較します。

完全な例は次のようになります。

    const char* myType = @encode(typeof(myVar));//myVar declared somewhere
    if( [@"@" isEqualToString:@(myType)] || [@"#" isEqualToString:@(myType)] )
    {
        //myVar is object(id) or a Class
    }
    else if ( NSNotFound != [[NSString stringWithFormat:@"%s", myType] rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"{}"]].location )
    {
        //myVar is struct
    }
    else if ( [@"i" isEqualToString:@(myType)] )
    {
        //my var is int
    }

NSInteger は、32 ビット デバイスでは int を返し、64 ビット デバイスでは long を返すことに注意してください。エンコーディングの完全なリスト:

‘c’ - char
‘i’ - int
’s’ - short
‘l’ - long
‘q’ - long long
‘C’ - unsigned char
‘I’ - unsigned int
’S’ - unsigned short
‘L’ - unsigned long
‘Q’ - unsigned long long
‘f’ - float
‘d’ - double
‘B’ - C++ bool or a C99 _Bool
‘v’ - void
‘*’ - character string(char *)
‘@’ - object(whether statically typed or typed id)
‘#’ - class object(Class)
‘:’ - method selector(SEL)
‘[<some-type>]’ - array
‘{<some-name>=<type1><type2>}’ - struct
‘bnum’ - bit field of <num> bits
‘^type’ - pointer to <type>
‘?’ - unknown type(may be used for function pointers)

Apple の Type Encodings の詳細を読む

于 2014-10-03T11:24:44.813 に答える
0

id は任意の Objective-C オブジェクトを表すことに注意してください。Objective-C オブジェクトとは、@interface を使用して定義されたものを意味します。構造体またはプリミティブ型 (int、char など) を表していません。

また、メッセージ ([...] 構文) は Objective-C オブジェクトにしか送信できないため、isKindOf: メッセージを通常の構造体またはプリミティブに送信することはできません。

ただし、整数などを NSNumber に変換したり、char* を NSString に変換したり、構造体を NSObject 派生クラス内にラップしたりできます。次に、Objective-C オブジェクトになります。

于 2012-04-06T17:24:03.150 に答える