Как я могу проверить конкретное свойство во время выполнения вместе с его возвращаемым типом?

Поскольку свойство с именем «возраст» всегда будет иметь селектор с именем «возраст», я мог бы использовать respondsToSelector как этот вопрос предлагает, и это скажет мне, существует ли конкретный селектор во время выполнения в любом данном объекте.

Если свойство с именем «возраст» существует, я могу это проверить. Как я могу узнать, возвращает ли этот селектор (метод чтения для этого свойства) объект (id) или не объект (int)?

Возможно ли такое определение типа во время выполнения, или цель-C всегда предполагает, что кто-то реализовал этот метод, используя тип, который, как я надеюсь, он использовал, или я также могу проверить возвращаемый тип?

Это использует последнюю версию Objective-C (LLVM 4.1) в XCode 4.5.

Обновление: это категория утилит на NSObject, которую я придумал:

   - (NSString*) propertyType: (NSString*)propname
{
    objc_property_t aproperty = class_getProperty([self class],  [propname cStringUsingEncoding:NSASCIIStringEncoding] ); // how to get a specific one by name.
    if (aproperty)
    {
     char * property_type_attribute = property_copyAttributeValue(aproperty, "T");
     NSString *result = [NSString stringWithUTF8String:property_type_attribute];
     free(property_type_attribute);
     return result;
    }
    else
        return nil;
}

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

- (NSArray*) properties;
{
    NSMutableArray *results = [NSMutableArray array];
    @autoreleasepool {

        unsigned int outCount, i;
        objc_property_t *properties = class_copyPropertyList([self class], &outCount);
        for (i = 0; i < outCount; i++) {
            objc_property_t property = properties[i];
            const char * aname=property_getName(property);
            [results addObject:[NSString stringWithUTF8String:aname]];
            //const char * attr= property_getAttributes(property);
            //[results addObject:[NSString stringWithUTF8String:attr]];

        }
        if (properties) {
            free(properties);
        }

  } // end of autorelease pool.
  return results;
}

person Warren P    schedule 14.01.2013    source источник
comment
Я думаю, вам нужно добавить if (properties) free(properties); к вашему удобному методу утилиты категории денди   -  person DonnaLea    schedule 21.05.2014
comment
Вероятно, правильно. Я не занимался кодированием на Objective-C несколько месяцев и чувствую себя довольно ржавым. Я тоже не уверен на 100%, что ты прав. :-) Мне может потребоваться некоторое чтение во время выполнения Objective-C, чтобы понять это в любом случае.   -  person Warren P    schedule 22.05.2014
comment
Я написал свою собственную категорию, прежде чем делать то же самое, и мне тоже пришлось исправить это для себя. Только что заметил, что теперь он смотрит на документацию немного ближе, увидев ответ Карла, в котором упоминается free() для использования property_copyAttributeValue.   -  person DonnaLea    schedule 22.05.2014
comment
Ладно, поверю тебе на слово. Можете ли вы отредактировать код, пожалуйста (отредактируйте мой пост), и я одобрю его, если ваш представитель слишком низкий   -  person Warren P    schedule 22.05.2014
comment
Спасибо за редактирование, DonnaLea!   -  person Warren P    schedule 29.05.2014


Ответы (2)


Один из подходов, который вы можете использовать, предполагая, что вы уже знаете имя свойства, заключается в использовании функции class_getProperty. Вы также можете использовать функцию property_copyAttributeValue(), чтобы получить только определенный атрибут по имени:

objc_property_t number_property = class_getProperty([MyClass class], "number");
char *number_property_type_attribute = property_copyAttributeValue(number_property, "T");
NSLog(@"number property type attribute = %s", number_property_type_attribute);

Зарегистрирует:

2013-01-14 14:45:37.382 RuntimeFun[61304:c07] числовой атрибут типа свойства = i

Предполагая, что MyClass выглядит примерно так:

@interface MyClass : NSObject
@property (nonatomic) int number;
@end

@implementation MyClass
@end

Получив строку атрибута типа, вы можете сравнить ее с различными Кодировки типа Objective-C. Когда вы закончите сравнение, обязательно вызовите free() в строке атрибута.

person Carl Veazey    schedule 14.01.2013
comment
property_copyAttributeValue(x,"T") был именно тем, что я искал. - person Warren P; 15.01.2013
comment
Я написал это как служебную категорию в своем вопросе вместе с free(attribute). - person Warren P; 15.01.2013
comment
@WarrenP отлично! Следует иметь в виду одну вещь, вы как бы намекаете на это в своем вопросе, это проверить фактическую реализацию свойства. Вы можете проверить, используются ли пользовательские геттеры или сеттеры, проверив типы атрибутов G и S соответственно. И может потребоваться особая осторожность для динамических свойств (тип D возвращает пустую строку, а не NULL) - я не совсем уверен, как проверить, что у них есть реализация, я полагаю, проверка селектора в порядке, но я не знаю, как это будет работать с NSManagedObject подкассами, которые используют KVC для своих свойств, в первую очередь. - person Carl Veazey; 15.01.2013
comment
Я думаю, что для того, чтобы на самом деле ВЫЗЫВАТЬ такие вещи во время выполнения, KVC - это то, что нужно. Я просто собираюсь использовать это для проверки подписей во время выполнения, это объект со свойством имени, которое возвращает строку? Да? Тогда это именованный объект для моих целей. Если я хочу что-то читать, я буду полагаться исключительно на KVC. - person Warren P; 15.01.2013

Вы можете использовать class_copyPropertyList для получения списка свойств, объявленных в классе.

class_copyPropertyList

Описывает свойства, объявленные классом.

А потом property_getAttributes:

свойство_getAttributes

Возвращает строку атрибута свойства.

Здесь вы можете найти более конкретные советы и примеры.

В качестве примечания следующее утверждение:

Поскольку свойство с именем age всегда будет иметь селектор с именем age

неверно, так как свойство может иметь собственный геттер и/или сеттер:

@property (nonatomic, getter=isImmediate) BOOL immediate;

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

Пример кода, который я нашел в другое ТАК сообщение:

const char * type = property_getAttributes(class_getProperty([self class], "myPropertyName"));
NSString * typeString = [NSString stringWithUTF8String:type];
NSArray * attributes = [typeString components separatedByString:@","];
NSString * typeAttribute = [attributes objectAtIndex:0];
NSString * propertyType = [typeAttribute substringFromIndex:1];
const char * rawPropertyType = [propertyType UTF8String];

if (strcmp(rawPropertyType, @encode(float)) == 0) {
 //it's a float
} else if (strcmp(rawPropertyType, @encode(int)) == 0) {
 //it's an int
} else if (strcmp(rawPropertyType, @encode(id)) == 0) {
 //it's some sort of object
} else ....
person sergio    schedule 14.01.2013
comment
Я думал, что частью контракта является то, что свойство abc должно иметь селектор чтения abc. Не так? - person Warren P; 15.01.2013
comment
вы можете переопределить этот контракт и указать желаемое имя. посмотрите на пример. Я не думаю, что в этом случае у вас также будет селектор immediate рядом с isImmediate. - person sergio; 15.01.2013
comment
Таким образом, property_getAttributes возвращает много вещей в виде (char *), есть ли прямой способ проверить тип: BOOL? - person Warren P; 15.01.2013
comment
Я так не думаю, но я нашел пример кода, который может помочь... проверьте мое редактирование. - person sergio; 15.01.2013
comment
Из этого связанного вопроса кажется, что бокс во время выполнения может быть более идиоматичным, чем выполнение этого с помощью грубой силы: stackoverflow.com/questions/3497625/ - person Warren P; 15.01.2013