Динамические геттеры и сеттеры с Objective C - PullRequest
2 голосов
/ 17 июля 2011

Я нахожусь в ситуации, когда я хочу динамически генерировать методы получения и установки для класса во время выполнения (аналогично тому, что NSManagedObject делает за кулисами).Насколько я понимаю, это возможно с использованием resolInstanceMethod: для конкретного класса.На этом этапе вам нужно будет использовать class_addMethod для динамического добавления метода на основе селектора.Я понимаю это на теоретическом уровне, но я не особо углублялся в среду выполнения obj-c, поэтому мне было любопытно, есть ли замечательные примеры того, как это сделать.Большая часть моих знаний приходит из этой статьи:

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html

Есть мысли / примеры?

Ответы [ 2 ]

9 голосов
/ 17 июля 2011

Единственное приятное обсуждение, которое я знаю, это запись в блоге Майка Эша . На самом деле это не так сложно.

Мне когда-то нужно было разделить большой подкласс NSManagedObject на два, но я решил оставить этот факт в деталях реализации, чтобы мне не приходилось переписывать другие части моего приложения. Итак, мне нужно было синтезировать геттер и сеттер, который автоматически отправляет [self foo] в [self.data foo].

Для этого я сделал следующее:

  1. Подготовьте новый метод, уже в моем классе.

    - (id)_getter_
    {
        return objc_msgSend(self.data, _cmd);
    }
    
    - (void)_setter_:(id)value 
    {
        objc_msgSend(self.data, _cmd,value);
    }
    

    Обратите внимание, что в _cmd есть селектор. Таким образом, обычно _cmd является либо @selector(_getter_), либо @selector(_setter_) в этих методах, но я собираюсь включить реализацию _getter_ как реализацию foo. Затем _cmd содержит @selector(foo) и, таким образом, вызывает self.data s foo.

  2. Напишите общий метод синтеза:

    +(void)synthesizeForwarder:(NSString*)getterName
    {
        NSString*setterName=[NSString stringWithFormat:@"set%@%@:",
              [[getterName substringToIndex:1] uppercaseString],[getterName substringFromIndex:1]];
        Method getter=class_getInstanceMethod(self, @selector(_getter_));
        class_addMethod(self, NSSelectorFromString(getterName), 
                        method_getImplementation(getter), method_getTypeEncoding(getter));
        Method setter=class_getInstanceMethod(self, @selector(_setter_:));
        class_addMethod(self, NSSelectorFromString(setterName), 
                        method_getImplementation(setter), method_getTypeEncoding(setter));
    }
    

    Обратите внимание, что это метод класса. Таким образом, self обозначает класс. Также обратите внимание, что я не жестко кодировал типы кодов (которые сообщают среде выполнения Objective C, каковы аргументы конкретного метода). Синтаксис кодирования типов задокументирован, но создание вручную очень подвержено ошибкам; Я потратил впустую несколько дней, пока Майк Эш не сказал мне прекратить это. Сгенерируйте его, используя существующий метод.

  3. Создание форвардеров в кратчайшие сроки:

     +(void)load  
     {
         for(NSString*selectorName in [NSArray arrayWithObjects:@"foo", @"bar", @"baz",nil]){
            [self synthesizeForwarder:selectorName];
         }
     }
    

    Генерирует foo, setFoo:, bar, setBar: и baz, setBaz:.

Надеюсь, это поможет!

5 голосов
/ 17 июля 2011

Другой пример, который я написал, называется DynamicStorage и доступен здесь:

https://github.com/davedelong/Demos

Основным стимулом для этого был этот вопрос , в котором спрашивалось, как использовать NSMutableDictionary в качестве резервного хранилища для любого объекта ivar. Я написал класс, который будет генерировать геттеры и сеттеры для любого @property, уважая такие вещи, как пользовательское имя геттера / сеттера, политику управления памятью объекта и т. Д. В этом есть хорошая вещь: он использует imp_implementationWithBlock(), так что он только должен вычислить соответствующее имя свойства один раз (а затем захватывает и сохраняет его как часть блока).

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