检查对象是否是类类型

时间:2022-12-21 17:00:42

I have a method that receives a NSArray of Class objects and I need to check if they all are Class type generated with the code bellow:

我有一个接收类对象NSArray的方法,我需要检查它们是否都是用下面的代码生成的类类型:

NSMutableArray *arr = [[NSMutableArray alloc] init];

[arr addObject:[NSObject class]];
[arr addObject:[NSValue class]];
[arr addObject:[NSNumber class]];
[arr addObject:[NSPredicate class]];
[arr addObject:@"not a class object"];

The problem is that Class is not an objective-c class, it is a struc, so I can not use just

问题是类不是objective-c类,而是struc,所以我不能只使用它

    for (int i; i<[arr count]; i++) {
        Class obj = [arr objectAtIndex:i];

        if([obj isKindOfClass: [Class class]]) {
            //do sth
        }
    }

So, I need to I check if the obj variable is a Class type, I suppose it will be in C directly, but how can I do that?

我需要检查obj变量是否是类类型,我想它会在C中,但是我怎么做呢?

It will be a plus if the answer also provide a way to check if the item in the array is a NSObject, as the items in the example code, the NSPredicate would also be true for the NSObject check

如果答案还提供了一种检查数组中的项是否为NSObject的方法,那么它将是一个加号,就像示例代码中的项一样,NSPredicate对于NSObject检查也是正确的

6 个解决方案

#1


45  

To determine if an "object" is a class or an instance you need to check if it is a meta class in a two stage process. First call object_getClass then check if it is a meta class using class_isMetaClass. You will need to #import <objc/runtime.h>.

要确定一个“对象”是一个类还是一个实例,您需要检查它是否是两个阶段过程中的一个元类。首先调用object_getClass,然后使用class_isMetaClass检查它是否是一个元类。您将需要#import

NSObject *object = [[NSObject alloc] init];
Class class = [NSObject class];

BOOL yup = class_isMetaClass(object_getClass(class));
BOOL nope = class_isMetaClass(object_getClass(object));

Both Class and *id have the same struct layout (Class isa), therefore can pose as objects and can both receive messages making it hard to determine which is which. This seems to be the only way I was able to get consistent results.

类和*id都具有相同的结构布局(类isa),因此它们都可以摆成对象,并且都可以接收消息,这使得很难确定哪个是哪个。这似乎是我获得一致结果的唯一途径。

EDIT:

编辑:

Here is your original example with the check:

这是你的原始例子,支票:

NSMutableArray *arr = [[NSMutableArray alloc] init];

[arr addObject:[NSObject class]];
[arr addObject:[NSValue class]];
[arr addObject:[NSNumber class]];
[arr addObject:[NSPredicate class]];
[arr addObject:@"not a class object"];

for (int i; i<[arr count]; i++) {
    id obj = [arr objectAtIndex:i];

    if(class_isMetaClass(object_getClass(obj)))
    {
        //do sth
        NSLog(@"Class: %@", obj);
    }
    else
    {
        NSLog(@"Instance: %@", obj);
    }
}

[arr release];

And the output:

和输出:

Class: NSObject
Class: NSValue
Class: NSNumber
Class: NSPredicate
Instance: not a class object

类:NSObject类:NSValue类:NSNumber类:NSPredicate实例:不是类对象。

#2


8  

Update: In iOS 8+ or OS X 10.10+, you can just do:

更新:在iOS 8+或OS X 10.10+中,你只需要:

object_isClass(obj)

(You will need to #import <objc/runtime.h>.)

(您需要#import 。)

#3


4  

Joe’s answer is good. A simple alternative that works in most situations is to check if the object returns itself in response to class.

乔的回答是好的。在大多数情况下,一个简单的替代方法是检查对象是否返回自己以响应类。

if ([obj class] == obj) { … }

This works because the NSObject meta-class overrides class and returns the class object (itself) — see the NSObject Class Reference. This does not require the runtime headers, but assumes the objects are subclasses of NSObject and don’t override -class or +class and do something unusual.

这是因为NSObject元类覆盖类并返回类对象(本身)——请参见NSObject类引用。这并不需要运行时标头,但是假设对象是NSObject的子类,并且不重写-类或+类,并做一些不寻常的事情。


With the input in the question, the results are the same as Joe’s:

有了问题的输入,结果和Joe的一样:

NSMutableArray *arr = [[NSMutableArray alloc] init];

[arr addObject:[NSObject class]];
[arr addObject:[NSValue class]];
[arr addObject:[NSNumber class]];
[arr addObject:[NSPredicate class]];
[arr addObject:@"not a class object"];

for (id<NSObject> obj in arr) {

    if ([obj class] == obj) {
        NSLog(@"Class: %@", obj);
    }
    else {
        NSLog(@"Instance: %@", obj);
    }
}

Class: NSObject
Class: NSValue
Class: NSNumber
Class: NSPredicate
Instance: not a class object

类:NSObject类:NSValue类:NSNumber类:NSPredicate实例:不是类对象。

#4


1  

If you need to verify if the object in the array is a Class object then you can verify if it responds to class methods.

如果需要验证数组中的对象是否是类对象,那么可以验证它是否响应类方法。

for ( id obj in arr ) {
    if (([obj respondsToSelector:@selector(isSubclassOfClass:)])
          && (obj == [NSObject class]) ) {
        NSLog(@"%@", obj);
    }
}

Once you know it is a Class object by verifying if it responds to isSubclassOfClass: then you can check for direct equality with [NSObject class].

一旦您通过验证它是否响应isSubclassOfClass来知道它是一个类对象:然后您可以检查它与[NSObject类]的直接相等性。

#5


-2  

The detail is comming.

细节,请等待。

First, In objc.h, we can find these codes:

首先,在objc。h,我们可以找到这些代码:

/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;

that means all Objective-C class is Class type, including NSObject.

这意味着所有Objective-C类都是类类型,包括NSObject。

so your question:

所以你的问题:

[arr addObject:[NSObject class]]; /// YES
[arr addObject:[NSValue class]];  /// YES
[arr addObject:[NSNumber class]];   /// YES
[arr addObject:[NSPredicate class]];   /// YES
[arr addObject:@"not a class object"];   /// NO, It's just a NSString.

Second, As you have mentioned, "Class is not an objective-c class, it is a struct". I want to explain that all objective-c class are Struct in C actually.

第二,正如您所提到的,“类不是一个objective-c类,而是一个struct”。我想解释所有objective-c类实际上都是C中的Struct。

In runtime.h, I find these codes, maybe help us:

在运行时。h,我发现了这些代码,或许可以帮助我们:

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;

Finally let's come to NSObject.h line30--32, these three methods. We can know that aClass is Class type. That further illustrates that all objective-c class is Class type.

最后我们来看看NSObject。h行30- 32,这三种方法。我们可以知道aClass是类类型。这进一步说明了objective-c类都是类类型。

- (BOOL)isKindOfClass:(Class)aClass;
- (BOOL)isMemberOfClass:(Class)aClass;
- (BOOL)conformsToProtocol:(Protocol *)aProtocol;

It's almost my first time to answer question in my poor English. If you also have any questions, please reply soon, I will try my best to explain it. And I also suggest you to read NSObject.h, runtime.h, objc.h code, maybe it will help you.

这几乎是我第一次用我蹩脚的英语回答问题。如果您还有什么问题,请尽快回复,我会尽力解释的。我也建议你们读NSObject。h,运行时。h,objc。h代码,可能会对你有帮助。

#6


-4  

No problem here is how you do it:

这里没有问题是你怎么做的:

if([NSStringFromClass([obj class]) isEqualToString:@"Class"]){
    NSLog(@"It is type of Class");
}

Edit

编辑

Or you can make your Class conform to a protocol: and check if obj that you get from the array conforms to this protocol like this:

或者你可以让你的类符合一个协议:检查你从数组中得到的obj是否符合这个协议,比如:

if([obj conformsToProtocol:@protocol(MyClassProtocol)])

Edit

编辑

Or you can check if what you get from the array is an NSObject complient

或者您可以检查从数组中获得的内容是否为NSObject遵从性

if ([object conformsToProtocol:@protocol(NSObject)]) {
    // Do something
}

#1


45  

To determine if an "object" is a class or an instance you need to check if it is a meta class in a two stage process. First call object_getClass then check if it is a meta class using class_isMetaClass. You will need to #import <objc/runtime.h>.

要确定一个“对象”是一个类还是一个实例,您需要检查它是否是两个阶段过程中的一个元类。首先调用object_getClass,然后使用class_isMetaClass检查它是否是一个元类。您将需要#import

NSObject *object = [[NSObject alloc] init];
Class class = [NSObject class];

BOOL yup = class_isMetaClass(object_getClass(class));
BOOL nope = class_isMetaClass(object_getClass(object));

Both Class and *id have the same struct layout (Class isa), therefore can pose as objects and can both receive messages making it hard to determine which is which. This seems to be the only way I was able to get consistent results.

类和*id都具有相同的结构布局(类isa),因此它们都可以摆成对象,并且都可以接收消息,这使得很难确定哪个是哪个。这似乎是我获得一致结果的唯一途径。

EDIT:

编辑:

Here is your original example with the check:

这是你的原始例子,支票:

NSMutableArray *arr = [[NSMutableArray alloc] init];

[arr addObject:[NSObject class]];
[arr addObject:[NSValue class]];
[arr addObject:[NSNumber class]];
[arr addObject:[NSPredicate class]];
[arr addObject:@"not a class object"];

for (int i; i<[arr count]; i++) {
    id obj = [arr objectAtIndex:i];

    if(class_isMetaClass(object_getClass(obj)))
    {
        //do sth
        NSLog(@"Class: %@", obj);
    }
    else
    {
        NSLog(@"Instance: %@", obj);
    }
}

[arr release];

And the output:

和输出:

Class: NSObject
Class: NSValue
Class: NSNumber
Class: NSPredicate
Instance: not a class object

类:NSObject类:NSValue类:NSNumber类:NSPredicate实例:不是类对象。

#2


8  

Update: In iOS 8+ or OS X 10.10+, you can just do:

更新:在iOS 8+或OS X 10.10+中,你只需要:

object_isClass(obj)

(You will need to #import <objc/runtime.h>.)

(您需要#import 。)

#3


4  

Joe’s answer is good. A simple alternative that works in most situations is to check if the object returns itself in response to class.

乔的回答是好的。在大多数情况下,一个简单的替代方法是检查对象是否返回自己以响应类。

if ([obj class] == obj) { … }

This works because the NSObject meta-class overrides class and returns the class object (itself) — see the NSObject Class Reference. This does not require the runtime headers, but assumes the objects are subclasses of NSObject and don’t override -class or +class and do something unusual.

这是因为NSObject元类覆盖类并返回类对象(本身)——请参见NSObject类引用。这并不需要运行时标头,但是假设对象是NSObject的子类,并且不重写-类或+类,并做一些不寻常的事情。


With the input in the question, the results are the same as Joe’s:

有了问题的输入,结果和Joe的一样:

NSMutableArray *arr = [[NSMutableArray alloc] init];

[arr addObject:[NSObject class]];
[arr addObject:[NSValue class]];
[arr addObject:[NSNumber class]];
[arr addObject:[NSPredicate class]];
[arr addObject:@"not a class object"];

for (id<NSObject> obj in arr) {

    if ([obj class] == obj) {
        NSLog(@"Class: %@", obj);
    }
    else {
        NSLog(@"Instance: %@", obj);
    }
}

Class: NSObject
Class: NSValue
Class: NSNumber
Class: NSPredicate
Instance: not a class object

类:NSObject类:NSValue类:NSNumber类:NSPredicate实例:不是类对象。

#4


1  

If you need to verify if the object in the array is a Class object then you can verify if it responds to class methods.

如果需要验证数组中的对象是否是类对象,那么可以验证它是否响应类方法。

for ( id obj in arr ) {
    if (([obj respondsToSelector:@selector(isSubclassOfClass:)])
          && (obj == [NSObject class]) ) {
        NSLog(@"%@", obj);
    }
}

Once you know it is a Class object by verifying if it responds to isSubclassOfClass: then you can check for direct equality with [NSObject class].

一旦您通过验证它是否响应isSubclassOfClass来知道它是一个类对象:然后您可以检查它与[NSObject类]的直接相等性。

#5


-2  

The detail is comming.

细节,请等待。

First, In objc.h, we can find these codes:

首先,在objc。h,我们可以找到这些代码:

/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;

that means all Objective-C class is Class type, including NSObject.

这意味着所有Objective-C类都是类类型,包括NSObject。

so your question:

所以你的问题:

[arr addObject:[NSObject class]]; /// YES
[arr addObject:[NSValue class]];  /// YES
[arr addObject:[NSNumber class]];   /// YES
[arr addObject:[NSPredicate class]];   /// YES
[arr addObject:@"not a class object"];   /// NO, It's just a NSString.

Second, As you have mentioned, "Class is not an objective-c class, it is a struct". I want to explain that all objective-c class are Struct in C actually.

第二,正如您所提到的,“类不是一个objective-c类,而是一个struct”。我想解释所有objective-c类实际上都是C中的Struct。

In runtime.h, I find these codes, maybe help us:

在运行时。h,我发现了这些代码,或许可以帮助我们:

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;

Finally let's come to NSObject.h line30--32, these three methods. We can know that aClass is Class type. That further illustrates that all objective-c class is Class type.

最后我们来看看NSObject。h行30- 32,这三种方法。我们可以知道aClass是类类型。这进一步说明了objective-c类都是类类型。

- (BOOL)isKindOfClass:(Class)aClass;
- (BOOL)isMemberOfClass:(Class)aClass;
- (BOOL)conformsToProtocol:(Protocol *)aProtocol;

It's almost my first time to answer question in my poor English. If you also have any questions, please reply soon, I will try my best to explain it. And I also suggest you to read NSObject.h, runtime.h, objc.h code, maybe it will help you.

这几乎是我第一次用我蹩脚的英语回答问题。如果您还有什么问题,请尽快回复,我会尽力解释的。我也建议你们读NSObject。h,运行时。h,objc。h代码,可能会对你有帮助。

#6


-4  

No problem here is how you do it:

这里没有问题是你怎么做的:

if([NSStringFromClass([obj class]) isEqualToString:@"Class"]){
    NSLog(@"It is type of Class");
}

Edit

编辑

Or you can make your Class conform to a protocol: and check if obj that you get from the array conforms to this protocol like this:

或者你可以让你的类符合一个协议:检查你从数组中得到的obj是否符合这个协议,比如:

if([obj conformsToProtocol:@protocol(MyClassProtocol)])

Edit

编辑

Or you can check if what you get from the array is an NSObject complient

或者您可以检查从数组中获得的内容是否为NSObject遵从性

if ([object conformsToProtocol:@protocol(NSObject)]) {
    // Do something
}