2012-02-23 2 views
4

У меня есть класс, который по существу действует как класс оболочки легкого веса вокруг другого класса. Он считает, что другой класс как iVar. Я хочу, чтобы иметь возможность выставить определенные свойства (очень немногие на самом деле) из Ивар, но для этого я должен выписать каждое свойство аксессор так:Отображение/синтезация свойств iVar в Objective c

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

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

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

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

+0

Взгляните на этот вопрос (и мой собственный ответ на него): http://stackoverflow.com/questions/8763028/ Очень хороший вопрос! –

+0

@ RichardJ.RossIII Спасибо за помощь. Сообщение на mikeash.com действительно помогло мне разобраться в этом вопросе. Я отправил ответ. –

ответ

4

Итак, вот решение, которое я нашел ... оказалось довольно простым, как только вы знали, что делать. Первая перезапись «- (идентификатор) forwardingTargetForSelector: (SEL) aSelector» и вернуть Ивар:

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

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

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

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

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

Теперь единственный недостаток, который я вижу, заключается в том, что если вы изменяете какие-либо свойства в интерфейсе iVar Class, вам нужно убедиться, что вы обновляете все другие классы, которые используют описанный выше метод, в противном случае вы столкнетесь, когда другой класс пытается отправить то, что теперь является неправильным методом (и компилятор не предупредит вас заранее). Тем не менее, это может быть получено. Вы можете объявлять протоколы в категории. Поэтому вместо этого вы создаете отдельный протокол для класса 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 

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

2

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

- (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, в противном случае компилятор будет жаловаться, что ваш класс не реализует эти методы. Конечно, было бы лучше, если бы вы могли придумать какой-нибудь лучший дизайн, который обойдется без таких трюков.

+0

Однако для этого нельзя использовать точечные обозначения, так как для этого не было бы правильного интерфейса. –

+0

Да. Вы можете отнести объект к классу ivar, что иногда имеет смысл и сделает компилятор счастливым даже с точечной нотацией. – zoul

+0

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

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