Как проверить существование свойства и тип на основе типизированного ключа NSString? - PullRequest
5 голосов
/ 10 февраля 2011

В моем стремлении обновить модель Core Data в моем проекте iOS я запрашиваю сервер для объектов JSON, которые в некоторой степени соответствуют управляемым объектам моей модели.Конечный результат, к которому я стремлюсь, - это надежное решение для обновления выходных данных JSON.

В качестве примеров в этом вопросе я назову управляемый объект основных данных existingObj и входящий десериализованный словарь JSON updateDict.Сложная часть имеет дело с этими фактами:

  1. Не все свойства existingObj присутствуют в updateDict
  2. Не все свойства updateDict доступны вextistingObj.
  3. Не все типы свойств existingObj соответствуют десериализованным свойствам JSON.(для некоторых строк может потребоваться пользовательская оболочка Objective-C).
  4. updateDict может содержать значения для неинициализированных ключей (nil) в existingObj.

Thisозначает, что при переборе обновленных словарей необходимо провести некоторое тестирование свойств туда-сюда.Сначала я должен проверить, существуют ли свойства updateDict в existingObj, затем я устанавливаю значение с помощью KVC, например:

// key is an NSString, e.g. @"displayName"
if ([existingObj respondsToSelector:NSSelectorFromString(key)) {
    [existingObj setValue:[updateDict objectForKey:key] forKey:key];
}

Хотя эта часть работает, мне не нравитсяДело в том, что я на самом деле тестирую displayName как получатель, а я собираюсь вызвать установщик setDisplayName: (косвенно через KVC).Я предпочел бы что-то вроде [существующий_объект hasWritablePropertyWithName : ключ], но что-то, что делает это, я не могу найти.

Это относится к подзапросу A: Как выполнить один тест для установщика свойства, если у вас есть только имя свойства?

Следующая часть - то, где я хотел быавтоматизировать идентификацию имущества на основе их типов.Если и у updateDict, и у existingObj есть NSString для ключа @ "displayName", установить новое значение легко.Однако, если updateDict содержит NSString для ключа @ "color", который является @ "niceShadeOfGreen", я хотел бы преобразовать это в правильный экземпляр UIColor.Но как мне проверить тип получающего свойства в existingObj, чтобы я знал, когда преобразовывать значения, а когда просто назначать?Я надеялся на что-то вроде typeOfSelector:

if ([existingObj typeOfSelector:sel] == [[updateDict objectForKey:key] class]) {
     // regular assignment
} else {
     // perform custom assignment
}

Конечно, это фиктивный код.Я не могу полагаться на тестирование типа значения existingObj -объекта, поскольку оно может быть унифицированным или nil.

Подвопрос B: Как проверить один тип свойства, если у вас есть только имя свойства?

Полагаю, все.Я подумал, что это, должно быть, дурак чего-то, что уже здесь, но я не смог его найти.Может быть, вы, ребята, можете?
Cheers, EP.

PS Если у вас есть лучший способ синхронизации пользовательских объектов Objective C с десериализованными объектами JSON, пожалуйста, поделитесь!В конце концов, результат имеет значение.

1 Ответ

27 голосов
/ 10 февраля 2011

Если вы хотите запросить, есть ли у объекта установщик для данного ключа KVC с именем key, который соответствует объявленному свойству, вам необходимо проверить, отвечает ли он методу выбора с именем setKey: (начинается с set, используйте первый символ в key, добавьте в конце двоеточие. Например,

NSString *key = @"displayName";
NSString *setterStr = [NSString stringWithFormat:@"set%@%@:",
                       [[key substringToIndex:1] capitalizedString],
                      [key substringFromIndex:1]];

if ([obj respondsToSelector:NSSelectorFromString(setterStr)]) {
    NSLog(@"found the setter!");
    [obj setValue:someValue forKey:key];
}

Два замечания:

  • Несмотря на то, что свойства могут иметь установщики с именами, которые не соответствуют описанному выше шаблону, они не будут соответствовать KVC, поэтому можно проверить set<Key>:, так как вы используете KVC для установки соответствующее значение.

  • KVC не использует только метод установки. Если он не находит метод установки, он проверяет, разрешает ли класс прямой доступ к переменным экземпляра, и, если это так, использует переменную экземпляра для установки значения. Кроме того, если метод установки или переменная экземпляра не найдены, он отправляет -setValue:forUndefinedKey: получателю, чей класс мог переопределить стандартную реализацию, которая выдает исключение. Это описано в Руководство по программированию кодирования значения ключа . При этом, если вы всегда используете свойства, проверка метода установки должна быть безопасной.

Что касается вашего второго вопроса, невозможно запросить среду выполнения, чтобы узнать фактический класс Objective-C свойства. С точки зрения времени выполнения существует специфическая для реализации кодировка типов для свойств и общих типов (таких как параметры метода / возвращаемые типы). Эта кодировка типов использует одну кодировку (а именно @) для любого объекта Objective-C, поэтому кодировка типа свойства NSString такая же, как кодировка типа свойства UIColor, поскольку они оба Objective- С классы.

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

...