Экспонирование / синтезирование свойств iVar в Objective c - PullRequest
4 голосов
/ 23 февраля 2012

У меня есть класс, который, по сути, действует как легкий класс-оболочка для другого класса. Это другой класс как iVar. Я хочу показать некоторые свойства iVar (на самом деле их довольно много), но для этого мне нужно записать каждый метод доступа к свойствам следующим образом:

- (void) setProperty:(Class *)value{
    _iVar.property = value;
}
- (Class *) property{
    return  _iVar.property;
}

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

Можно ли синтезировать?

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

Ответы [ 2 ]

4 голосов
/ 23 февраля 2012

Хорошо, вот решение, которое я нашел ... оказалось довольно простым, когда вы знали, что делать.Сначала перезаписать '- (id) forwardingTargetForSelector: (SEL) aSelector' и вернуть iVar:

- (id) forwardingTargetForSelector:(SEL)aSelector{
    return iVar;
}

Когда среда выполнения ищет метод и не может его найти, он вызовет этот метод, чтобы проверить, есть лиеще один объект для пересылки сообщения.Обратите внимание, что этот метод обычно возвращает nil, и если вы вернете nil здесь, ваша программа потерпит крах (что является подходящим поведением).

Вторая часть проблемы заключается в том, чтобы скрыть ошибки / предупреждения компилятора, которые вы получите, когда попытаетесь отправить сообщение, которое не было объявлено.Это легко сделать, объявив категорию, которую вы не реализуете.

@interface Class (iVarClassMethods)
@propoperty (strong) Class *property1;
......more properties
@end

До тех пор, пока вы нигде не вставите реализацию, то есть @implementation Class (category), компилятор не будет жаловаться (он будет предполагать, что реализация где-то где-то ....).

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

@protocol iVarClassProtocol
@propoperty (strong) Class *property1;
......more properties
@end

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

@interface iVarClass <iVarClassProtocol>
....other methods/properties you don't need forwarded
@end

Наконец, просто добавьте протокол в категорию.Таким образом, вместо вышеупомянутой категории с явными объявлениями у вас будет:

@interface Class (iVarClassMethods) <iVarClassProtocol>
@end

Теперь, если вам нужно изменить какие-либо из свойств / методов, которые следует использовать, вы измените их в протоколе.Затем компилятор предупредит вас, когда вы попытаетесь отправить неправильный метод классу пересылки.

2 голосов
/ 23 февраля 2012

Я думаю, что вы можете пересылать сообщения в ivar:

- (void) forwardInvocation: (NSInvocation*) invocation
{
    [invocation invokeWithTarget:ivar];
}

- (NSMethodSignature*) methodSignatureForSelector: (SEL) selector
{
    NSMethodSignature *our = [super methodSignatureForSelector:selector];
    NSMethodSignature *ivars = [ivar methodSignatureForSelector:selector];
    return our ? our : ivars;
}

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

...