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