2012-06-02 2 views
3

У меня есть одноэлемент facade, который я бы хотел переслать вызовы методов класса в некоторый «статический» класс.forwardInvocation для другого класса, а не для экземпляра

На первый взгляд, forwardInvocation: оказалось возможное решение, однако, NSInvocation «s invokeWithTarget: и setTarget: только принять id, т.е.. е. указатель на экземпляр, а не сам класс. Я попытался передать [MyTargetClass class] в качестве цели, но до сих пор я получаю сообщение об ошибке «Неизвестный метод класса [...]», когда я вызываю [Facade someForwardedMethod]. Когда я звоню [[Facade sharedInstance] someForwardedMethod], я получаю «Нет видимого @interface [...] объявляет ошибку селектора [...]».

Конечно, я знаю, что мне также нужно переопределить respondsToSelector: и methodSignatureForSelector:, так что мой код выглядит следующим образом:

- (BOOL)respondsToSelector:(SEL)aSelector { 
    if ([super respondsToSelector:aSelector]) { 
     return YES; 
    } else { 
     return [MyTargetClass respondsToSelector:aSelector]; 
    } 
} 

- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { 
    NSMethodSignature* signature = [super methodSignatureForSelector:selector]; 
    if (!signature) { 
     signature = [MyTargetClass methodSignatureForSelector:selector]; 
    } 
    return signature; 
} 

- (void)forwardInvocation:(NSInvocation *)anInvocation { 

    SEL aSelector = [anInvocation selector]; 

    if ([MyTargetClass respondsToSelector: aSelector]) { 
     [anInvocation invokeWithTarget:[MyTargetClass class]]; 
    } else { 
     [super forwardInvocation:anInvocation]; 
    } 
} 

Есть ли способ, чтобы сделать эту работу, или я должен выбрать другой подход ?


EDIT: Я попробовал оба пути, что Роб Napier упоминает в своем ответе, вот мои выводы:

Я могу вызвать метод класса в моей целевой класс через экземпляр фасада с

[(id)[Facade sharedInstance] doSomethingClassyInTargetClass]; 

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

[(Class)[Facade class] doSomethingClassyInTargetClass]; 

, но затем он бросает «NSInvalidArgumentException» «[Фасад doSomethingClassyInTargetClass]: непризнанные селектор направлен класс [...]» во время выполнения. По-видимому, классные методы класса фасада решаются без уважения для , но ведь у него есть - спереди ...

+0

Правильно ли я понимаю, что вы пытаетесь перенаправить вызов экземпляра в класс? Есть ли какая-то причина, по которой вы не просто делаете свой Facade также синглом, чтобы вы могли перенаправлять экземпляры экземпляров на вызовы экземпляра и класса в класс? –

+0

На самом деле это было бы идеальным. Однако пересылка вызовов метода класса в этот другой класс была бы достаточно хорошей, если это возможно. Разве это не должно работать с тем же кодом? Я попробовал, и он тоже не работает. Я соответствующим образом изменил вопрос ... Я бы хотел избежать создания экземпляра другого класса, он огромный и не содержит ничего, что могло бы выиграть от него. – Stefan

+2

Объект класса ** является ** экземпляром; это пример его метакласса. Вам может потребоваться использовать бросок, чтобы убедить компилятор в этом. Кроме того, вы пробовали новый механизм быстрой пересылки '-forwardingTargetForSelector:'? –

ответ

5

Ах, когда вы добавили «No visible @interface [...]», объявляет селектор [...] ", все ясно.

Рассмотрите более простую форму с помощью только методов экземпляра. Вы реализуете -forwardInvocation:, и тогда у вас есть такой код:

[obj doSomething]; 

Теперь MyObject фактически не требовать doSomething в заголовке, даже если он ответит на него. Поэтому компилятор жалуется, что это, вероятно, не сработает. Исправление что:

[(id)obj doSomething]; 

Когда вы заявляете что-то id, компилятор прекращает проверки, является ли на самом деле реализует целевой селектор. Но также возможно, что no интерфейс объявляет doSomething. Затем компилятор снова подозрительно, что это, вероятно, опечатка и дает вам предупреждение. И «без интерфейса», я имею в виду «никакого интерфейса, к которому имеет доступ компилятор». У компилятора только доступ к интерфейсам в этом компилируемом модуле (т. Е. В файле .m и в заголовках, которые он включает). Поэтому вам нужно включить заголовок, который определяет этот селектор.

Теперь для классов, вы не можете использовать id, но вы должны быть в состоянии использовать Class для достижения той же вещи, такие как:

[(Class)MyClass doSomethingClassy]; 

Если можете увидеть код RNObserverManager образца с прошивкой : PTL Chapter 4, которая демонстрирует нечто подобное.

Вы также должны определенно посмотреть на forwardTargetForSelector:, что упоминает Кен Томамас.


Вы не должны бросить sharedInstance к id. Просто измените подпись, так как вы всегда будете использовать ее таким образом:

+ (id)sharedInstance; 
+0

Я пробовал и исправил свой вопрос с выводами. Не все это работает, как я надеялся, но я полагаю, что это достаточно хорошо для моих целей. Спасибо! – Stefan

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