Шаблон Objective-C для переменных экземпляра класса? - PullRequest
2 голосов
/ 23 августа 2011

Какой будет хороший шаблон в Objective-C для переменных класса, которые могут быть "переопределены" подклассами?

Переменные обычного класса обычно моделируются в Objective-C с использованием локальных статических переменных файла вместе с открытыми средствами доступа, определенными как методы класса.

Однако это, как и любые переменные класса, означает, что значение является общим для класса и всех его подклассов. Иногда для подкласса интересно изменить значение только для себя. Обычно это тот случай, когда переменные класса используются для конфигурации.

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

Во время выполнения пользователь может решить, что все аннотации Foo теперь будут иметь красную метку. И так далее.

Поскольку в Objective-C классы являются фактическими объектами, это требует сохранения цвета метки Foo в объекте класса Foo. Но возможно ли это? Что будет хорошим примером для такого рода вещей? Конечно, можно определить какой-то глобальный словарь, сопоставляющий класс с его значением конфигурации, но это было бы некрасиво.

Ответы [ 2 ]

1 голос
/ 24 августа 2011

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

Почему вы думаете, это было бы ужасно? Это очень простой подход, поскольку вы можете использовать [self className] в качестве ключа в словаре. Это также легко сделать постоянным, так как вы можете просто сохранить словарь в NSUserDefaults (при условии, что он содержит только объекты списка свойств). Вы также можете установить для каждого класса значения по умолчанию для значений его суперкласса, вызывая метод superclass, пока не найдете класс со значением.

+ (id)classConfigurationForKey:(NSString *)key {
    if(_configurationDict == nil) [self loadConfigurations]; // Gets stored values
    Class c = [self class];
    id value = nil;
    while(value == nil) {
        NSDictionary *classConfig = [_configurationDict objectForKey:[c className]];
        if(classConfig) {
            value = [classConfig objectForKey:key];
        }
        c = [c superclass];
    }
    return value;
}
+ (void)setClassConfiguration:(id)value forKey:(NSString *)key {
    if(_configurationDict == nil) [self loadConfigurations]; // Gets stored values
    NSMutableDictionary *classConfig = [_configurationDict objectForKey:[self className]];
    if(classConfig == nil) {
        classConfig = [NSMutableDictionary dictionary];
        [_configurationDict setObject:classConfig forKey:[self className]];
    }
    [classConfig setObject:value forKey:key];
}

Эта реализация не обеспечивает проверки, чтобы убедиться, что вы не перебираете верхний суперкласс, поэтому вам нужно убедиться, что для этого класса есть значение, чтобы избежать бесконечного цикла.

Если вы хотите хранить объекты, которые не могут быть сохранены в списке свойств, вы можете использовать метод для преобразования туда и обратно при доступе к словарю. Вот пример доступа к свойству labelColor, которое является объектом UIColor.

+ (UIColor *)classLabelColor {
    NSData *data = [self classConfigurationForKey:@"labelColor"];
    return [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
+ (void)setClassLabelColor:(UIColor *)color {
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:color];
    [self setClassConfiguration:data forKey:@"labelColor"];
}
0 голосов
/ 24 августа 2011

мой ответ здесь может помочь:

Каков рекомендуемый метод оформления приложения для iOS?

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

Обновление

Жан-Дени Мюйс: Это касается примера использования моего вопроса, но несам мой вопрос (шаблон для имитации переменных экземпляра класса).

вы правы, я не знал, насколько точно ваш пример смоделировал вашу проблему, и я подумал о том, чтобы прокомментировать это.

для более общего и многократно используемого решения, я бы, вероятно, просто написал глобальный словарь, обеспечивающий безопасность потоков, если ваши глобальные данные нетривиальны (как вы упомянули в своем ОП).Вы можете либо заполнить его в +initialize, либо лениво, введя метод класса.затем вы можете добавить несколько категорий к NSObject для доступа и изменения статических данных - сделайте это для синтаксической простоты.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...