我想编写一个函数或类似NSLog()的指令,它接受任何类型的变量,基元和对象。在那个功能中,我想区分那些。
我知道对象是如何工作的:
- (void)test:(id)object {
if ([object isKindOfClass:[NSString class]])
...
但是如何区分对象与结构甚至整数或浮点数。 类似的东西:
"isKindOfStruct:CGRect" or "isInt"
例如?
这可能吗? 我想,因为你可以将所有内容发送到NSLog(@“......”,对象,整数,结构),它一定是可能的吗?
感谢您的帮助!
修改
我的最终目标是实现某种多态性。
我希望能够调用我的函数:
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不存在,你甚至不能在基元上执行这样的方法。我也不确定“???”函数头中的泛型类型“value”。
这可能吗?
答案 0 :(得分: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的宏,无论x是什么类型,都不必担心格式字符串(以及与例如以与NSString相同的方式打印C字符串的相关崩溃)。它适用于Mac OS X和iOS。
答案 1 :(得分:3)
像NSLog()
这样的函数可以从作为第一个参数传递的格式字符串中告诉参数列表中的类型。因此,您不查询参数以确定其类型 - 您根据格式字符串确定您期望的类型,然后相应地解释参数。
答案 2 :(得分:3)
@alex灰色答案不起作用(或者至少在iOS SDK 8.0上不起作用)。你可以使用@ deepax11的答案,不过我想指出这个魔术宏怎么样?作品。它依赖于系统提供的类型编码。根据Apple文档:
为了协助运行时系统,编译器对字符串中每个方法的返回和参数类型进行编码,并将字符串与方法选择器相关联。它使用的编码方案在其他上下文中也很有用,因此可以使用@encode()编译器指令公开使用。给定类型规范时,@ encode()返回编码该类型的字符串。类型可以是基本类型,例如int,指针,标记结构或联合,或类名 - 实际上,任何类型都可以用作C sizeof()运算符的参数。
为了打破宏,我们先得到" typeOf"我们的变量,然后在该类型上调用@encode(),最后将返回值与' object'和'班级'编码表中的类型。
完整示例应如下所示:
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)
答案 3 :(得分:2)
您不能将C结构或基元作为id
类型的参数传递。为此,您必须将基元包装在NSNumber或NSValue对象中。
e.g。
[self test: [NSNumber numberWithInt: 3.0]];
id
被定义为指向Objective-C对象的指针。
答案 4 :(得分:1)
#define IS_OBJECT(x)(strchr(&#34; @#&#34;,@ encode( typeof (x))[0])!= NULL) 这个微型作品我在堆栈中的某处溢出。
答案 5 :(得分:0)
重要的是要注意id表示任何Objective-C对象。而Objective-C对象,我指的是使用@interface定义的对象。它不代表结构或基本类型(int,char等)。
此外,您只能向Objective-C对象发送消息([...]语法),因此您无法将isKindOf:消息发送到普通的结构或原语。
但是你可以将整数等转换为NSNumber,将char *转换为NSString并将结构包装在NSObject-dervied类中。然后它们将是Objective-C对象。