Подтвердить что ты не робот

Проверьте, является ли объект типом класса

У меня есть метод, который получает 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 проверить

4b9b3361

Ответ 1

Чтобы определить, является ли "объект" классом или экземпляром, вам нужно проверить, является ли он 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), поэтому могут представлять собой объекты и могут получать сообщения, затрудняющие определение того, что есть. Кажется, это единственный способ добиться последовательных результатов.

EDIT:

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

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
Экземпляр: не объект класса

Ответ 2

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

object_isClass(obj)

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

Ответ 3

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

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

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


При вводе в вопрос результаты совпадают с результатами Joes:

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
Класс: NSPredicate
Экземпляр: не объект класса

Ответ 4

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

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

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

Ответ 5

Детали отправляются.

Во-первых, In 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 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. Это еще раз иллюстрирует, что все классы objective-c имеют тип Class.

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

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

Ответ 6

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

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

Edit

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

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

Изменить

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

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