Проверьте, является ли объект типом Class - PullRequest
33 голосов
/ 30 июня 2011

У меня есть метод, который получает NSArray из Class объектов, и мне нужно проверить, все ли они типа Class, сгенерированные с помощью кода ниже:

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"];

Проблема в том, что Class не является классом Objective-C, это структура, поэтому я не могу использовать только

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

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

Итак, мне нужно проверить, является ли переменная obj типом Class, я полагаю, она будет в C напрямую, но как я могу это сделать?

Будет плюсом, если ответ также предоставит способ проверить, является ли элемент в массиве NSObject, поскольку в качестве элементов в примере кода NSPredicate также будет true для NSObject чек

Ответы [ 6 ]

46 голосов
/ 30 июня 2011

Чтобы определить, является ли «объект» классом или экземпляром, необходимо проверить, является ли он мета-классом в двухэтапном процессе.Сначала вызовите object_getClass, затем проверьте, является ли это метаклассом, используя class_isMetaClass.Вам нужно будет #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));

И Class, и *id имеют одинаковую структуру (Class isa), поэтому могут выступать в качестве объектов и могут получать сообщения, затрудняющиеопределить, что есть что.Похоже, что это единственный способ получить последовательные результаты.

РЕДАКТИРОВАТЬ:

Вот ваш оригинальный пример с проверкой:

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

И вывод:

Класс: NSObjectКласс: NSValueКласс: NSNumberКласс: NSPredicateЭкземпляр: не объект класса

8 голосов
/ 18 сентября 2014

Обновление: В iOS 8+ или OS X 10.10+ вы можете просто сделать:

object_isClass(obj)

(Вам нужно будет #import <objc/runtime.h>.)

5 голосов
/ 22 апреля 2015

Джо ответит хорошо. Простая альтернатива, которая работает в большинстве ситуаций, - это проверить, возвращает ли объект себя в ответ на class.

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

Это работает, потому что метакласс NSObject переопределяет class и возвращает объект класса (сам по себе) - см. NSObject Class Reference . Это не требует заголовков времени выполнения, но предполагает, что объекты являются подклассами NSObject и не переопределяют -class или +class и делают что-то необычное.


С вводом в вопросе результаты такие же, как у Джо:

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);
    }
}

Класс: NSObject
Класс: NSValue
Класс: NSNumber
Класс: NSP предикат
Экземпляр: не объект класса

1 голос
/ 30 июня 2011

Если вам нужно проверить, является ли объект в массиве объектом Class, тогда вы можете проверить, отвечает ли он на методы класса.

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

Как только вы узнаете, что это объект Classпроверяя, отвечает ли он на isSubclassOfClass:, вы можете проверить прямое равенство с [NSObject class].

0 голосов
/ 16 сентября 2016

Деталь приближается.

Во-первых, в objc.h мы можем найти эти коды:

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

означает, что все Objective-C class имеют тип Class, включая NSObject.

твой вопрос:

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

Во-вторых, как вы упомянули, «Class - это не objective-c class, это структура». Я хочу объяснить, что все objective-c class на самом деле Struct в C.

В runtime.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;

Наконец, давайте подойдем к NSObject.h line30--32, этим трем методам. Мы можем знать, что aClass является Class типом. Это дополнительно показывает, что весь класс target-c имеет тип Class.

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

Я почти впервые отвечаю на вопрос на моем плохом английском. Если у вас также есть какие-либо вопросы, пожалуйста, ответьте в ближайшее время, я постараюсь объяснить это. И я также предлагаю вам прочитать NSObject.h, runtime.h, objc.h код, может быть, это поможет вам.

0 голосов
/ 30 июня 2011

Нет проблем, вот как вы это делаете:

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

Редактировать

Или вы можете заставить свой класс соответствовать протоколу: и проверьте, соответствует ли объект obj, полученный из массива, этому протоколу следующим образом:

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

Редактировать

Или вы можете проверить, соответствует ли то, что вы получаете из массива, NSObject

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