Felipe Sabino
Felipe Sabino

Reputation: 18215

Check if object is Class type

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:

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

    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?

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

Upvotes: 33

Views: 23135

Answers (5)

Douglas Hill
Douglas Hill

Reputation: 1547

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.


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

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

Upvotes: 5

user102008
user102008

Reputation: 31313

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

object_isClass(obj)

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

Upvotes: 7

Joe
Joe

Reputation: 57179

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>.

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.

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

Upvotes: 46

Deepak Danduprolu
Deepak Danduprolu

Reputation: 44633

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].

Upvotes: 1

Cyprian
Cyprian

Reputation: 9453

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:

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

Edit

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

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

Upvotes: -4

Related Questions