5

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

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

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

Это означает, что при повторении через обновленные словари должно быть некоторое тестирование свойств взад и вперед. Сначала я должен проверить, существуют ли свойства 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). Я бы предпочел что-то вроде [existingObj hasWritablePropertyWithName : key], но что-то, что делает это, я не могу найти.

Это делает для подзапроса 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 
} 

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

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

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

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

+0

Я предлагаю вам просто запросить 'updateDict' для ключей * вы знаете * и игнорировать все остальное. – Costique

+0

В приведенном выше примере это действительно жизнеспособный вариант. Однако в сценарии реального мира это сделало бы изменения в управляемом объекте и обновления очень сложными. Объекты состоят из более чем 30 ключей/свойств, большинство из которых - NSString или NSNumber. Если решение вопроса выше, синхронизация не нуждается в модификации, когда примитивные типы добавляются или изменяются с обеих сторон. – epologee

ответ

27

Если вы хотите запросить, имеет ли объект сеттер для данного ключа КЦА называется 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]; 
} 

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

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

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

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

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

+0

Очень ценный вход @Bavarious. Я не думал о словаре с соответствующими типами, это самое элегантное решение sofar! Разве это не распространенная проблема при обновлении локальной модели от ответа сервера в JSON? Есть ли лучшие решения для синхронизации? Cheers, EP. – epologee

+0

На самом деле это будет тема для следующего вопроса, я закрою этот пока. Благодаря! – epologee

+0

Удивительный Баварий, спасибо – shabbirv

Смежные вопросы