Предположим (ради аргумента), что у меня есть класс представления, который содержит NSDictionary. Мне нужен целый набор свойств, все из которых имеют доступ к членам этого словаря.
Например, я хочу @property NSString * title
и @property NSString * author
.
Для каждого из этих свойств реализация одна и та же: для метода получения вызовите [dictionary objectForKey: propertyName];
, и для установщика сделайте то же самое с setObject: forKey:.
Потребовалось бы много времени и много кода для копирования и вставки, чтобы написать все эти методы. Есть ли способ генерировать их все автоматически, как это делают Core Data со свойствами @dynamic для подклассов NSManagedObject? Чтобы было ясно, я хочу, чтобы это средство доступа было доступно только для свойств, которые я определяю в заголовке, а не просто для произвольного ключа.
Я встречал valueForUndefinedKey: как часть кодирования значения ключа, которое может обрабатывать получатели, но я Я не совсем уверен, является ли это лучшим способом.
Мне нужно, чтобы это были явные свойства, чтобы я мог связать их в Интерфейсном Разработчике: я в конечном итоге планирую написать палитру IB для этого представления.
( Кстати, я знаю, что мой пример использования NSDictionary для их хранения немного надуман. Я на самом деле пишу подкласс WebView, и свойства будут ссылаться на идентификаторы элементов HTML, но это не важно для логики моего вопроса!)
Мне удалось решить эту проблему самостоятельно после того, как пролился на документацию среды выполнения objective-c.
Я реализовал этот метод класса:
+ (BOOL) resolveInstanceMethod:(SEL)aSEL
{
NSString *method = NSStringFromSelector(aSEL);
if ([method hasPrefix:@"set"])
{
class_addMethod([self class], aSEL, (IMP) accessorSetter, "v@:@");
return YES;
}
else
{
class_addMethod([self class], aSEL, (IMP) accessorGetter, "@@:");
return YES;
}
return [super resolveInstanceMethod:aSEL];
}
За ним следует пара функций C:
NSString* accessorGetter(id self, SEL _cmd)
{
NSString *method = NSStringFromSelector(_cmd);
// Return the value of whatever key based on the method name
}
void accessorSetter(id self, SEL _cmd, NSString* newValue)
{
NSString *method = NSStringFromSelector(_cmd);
// remove set
NSString *anID = [[[method stringByReplacingCharactersInRange:NSMakeRange(0, 3) withString:@""] lowercaseString] stringByReplacingOccurrencesOfString:@":" withString:@""];
// Set value of the key anID to newValue
}
Поскольку этот код пытается реализовать любой метод, который вызывается в классе и еще не реализован, это вызовет проблемы, если кто-то попытается Вы называете то, чего ожидаете от заметки. Я планирую добавить некоторую проверку здравомыслия, чтобы убедиться, что имена совпадают с тем, что я ожидаю.
похоже, вам следует использовать класс вместо словаря. вы приближаетесь к реализации вручную того, что язык пытается вам дать.
Вы можете использовать сочетание предложенных параметров:
Надеюсь, это поможет. Может показаться немного халтурным (с использованием рефлексии), но на самом деле это очень гибкое и к тому же абсолютно «легальное» решение проблемы...
PS: способ coredata возможен, но в вашем случае это было бы полным излишеством...
Подружиться с Макро? Это может быть не на 100% правильно.
#define propertyForKey(key, type) \
- (void) set##key: (type) key; \
- (type) key;
#define synthesizeForKey(key, type) \
- (void) set##key: (type) key \
{ \
[dictionary setObject];// or whatever \
} \
- (type) key { return [dictionary objectForKey: key]; }