Как определить, существует ли ключ для объекта, используя кодирование ключ-значение?


Я хотел бы проверить, имеет ли объект записываемое свойство @в iPhone SDK.

Один из возможных способов сделать это-проверить метод-valueForKey:, но это кажется довольно неэлегантным!

Пример:

  @try {
    id *value = [instance valueForKey:@"myProperty"];
  }
  @catch (NSException * e) {
    // Key did not exist
  }
Есть ли лучший способ сделать это?
3 37

3 ответа:

Если вы создаете проверяемый объект, вы можете переопределить valueForUndefinedKey: и setValue:forUndefinedKey, чтобы сделать что-то более полезное, чем создание исключения.

С другой стороны, если вы пытаетесь интроспектировать объекты, о которых вы не знаете во время выполнения, вам придется использовать методы среды выполнения для этого. Вы можете либо использовать саму среду выполнения objective-c и вызывать либо class_copyPropertyList, либо protocol_copyPropertyList и работать с ними, либо использовать Foundation и вызывать respondsToSelector на объекте для геттера/сеттеров KVC для данного свойство, например, для свойства foo вы бы назвали что-то вроде [someObject respondsToSelector:NSSelectorFromString(@"foo")];.

В общем случае нет способа определить, имеет ли объект значение для данного ключа. Экземпляр может решить возвратить значение для неопределенного ключа в противном случае из своего метода -valueForUndefinedKey:. Или он может позволить реализации по умолчанию создать исключение. Современные Objective-C (2.0) объекты часто объявляют соответствующие свойства в своем публичном API. Для этих объектов можно использовать class_copyPropertyList или protocol_copyPropertyList среды выполнения Objective-C, чтобы получить список доступных свойств. Вы также можете повторить поиск КВЦ список, тестирование через repondsToSelector: , если экземпляр отвечает на соответствующий метод геттера. Наконец, вы можете использовать class_copyIvarList среды выполнения, чтобы проверить ивары для соответствующего Ивара. Этомного работы, которую Выне должны делать . Это не гарантирует, что вы знаете, вызовет ли экземпляр объекта исключение при отправке сообщения valueForKey:, и это указывает на более серьезную проблему...

Если у вас есть коллекция объектов, которые должны все предоставлять значение для данного ключа, но некоторые этого не делают, у вас проблема с дизайном. Вы должны определить соответствующий интерфейс (a @protocol в Objective-C), который объявляет необходимые свойства. Затем вы можете проверить соответствие этому протоколу или использовать компилятор для выполнения некоторой проверки типов во время компиляции, чтобы убедиться, что экземпляр соответствует протоколу (если вы передаете отдельные экземпляры).

Следующий ответ от @Jason Coco.

Вот мое предложение о том, как проверить специально для селекторов "set" существование свойства, которое вы пытаетесь установить.

Это чистая грязь, но она работает, и я обнаружил, что использую ее. Вас предупредили..
NS_INLINE SEL _Nonnull IBPropertySetSelectorForPropertyName(NSString*_Nonnull propertyName)
{

    NSString* firstLetter = [propertyName substringToIndex:1];
    propertyName = [propertyName substringFromIndex:1];

    propertyName = [[NSString alloc] initWithFormat:@"set%@%@:",firstLetter.capitalizedString,propertyName];

    return NSSelectorFromString(propertyName);
}

Использование:

В swift: Затем добавьте фрагмент кода в заголовок моста:

let key = "someKey"    
let sel = IBPropertySetSelectorForPropertyName(key)

if SOMETHING.responds(to: sel) {SOMETHING.setValue(value, forKeyPath: key)}