Переопределить метод в одном экземпляре объекта - PullRequest
5 голосов
/ 02 июня 2011

Я не уверен, как это выразить, и я не смог найти ответ из-за своей неспособности найти слова, чтобы выразить то, что я ищу. (!)

В Java я делал что-то вроде этого (не помню):

JPanel myButton = new JPanel("Press me"){
    public void add(JComponent component){
        //override add method
    }
};

Но я не смог найти, как это сделать в Objective-C .. В моем поиске я обнаружил категории и странные символы ^ {} ...

Итак, как я могу переопределить метод (ы) во вновь созданном объекте?

(Например, переопределить -(BOOL)isEqual; во вновь созданном NSString*?)

Извините, если вопрос немного расплывчатый.

EDIT:

Очевидно, без подклассов:)

EDIT:

Можно также опубликовать мою проблему на случай, если у кого-то есть идея получше:

У меня есть несколько CCTransitions в COCOS2D, и я хочу получать уведомления, когда переход завершается. Дело в том, что, как только переход заканчивается, заканчивается - (void); метод вызывается (который является частью структуры класса CCTransition)

Я бы действительно хотел избежать подкласса класса CCTransition и переопределить метод finish, чтобы выполнить мою логику после завершения перехода:)

EDIT:

- (void) onEnterTransitionDidFinish; ... Я не могу поверить чему-то столь же удивительному, как это существовало, и я не сталкивался с этим во время поиска ......

Что означает вместо подкласса CCTransition переопределить этот метод в моем подклассе CCNode: D!

Ответы [ 3 ]

7 голосов
/ 02 июня 2011

Это все еще не будет очень чисто, но, если вы готовы сконцентрировать уродство, вы могли бы сделать что-то вроде (не проверено):

Method methodToReplace =
          [targetClass instanceMethodSignatureForSelector:@selector(methodToReplace)];
IMP implementationToSet =
          [someProxyClass instanceMethodForSelector:@selector(implementationYouWant)];

method_setImplementation(methodToReplace, implementationToSet);

Соответствующая справочная документация Цель-C Ссылка на время выполнения и, опционально, Ссылка на класс NSObject (поскольку это несколько упрощает некоторые вещи, хотя, например, вы можете использовать class_getInstanceMethod из среды выполнения, а не instanceMethodSigntureForSelector:).

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

Для справки, у меня была законная причина сделать такую ​​вещь только один раз: когда мы реализовали поддержку печати в приложении для iOS, с которым нужно было поддерживать совместимость как с OS 3.2, так и с 4.0.Вам необходимо создать подкласс определенного класса, но этот класс недоступен в 3.2.Таким образом, вы как бы вынуждены создавать подклассы во время выполнения (хотя концептуально более подходящим способом было бы использовать обычный подкласс, поместить его в среду и слабое звено, но термины Apple SDK iOS допускают только статические библиотеки, так что ...).

3 голосов
/ 02 июня 2011

Следуя совету Дэниела, вы можете реализовать метод в категории NSObject вида

[anObject overrideMethod:@selector(foo:) 
          byBlock:^(id self,id super,id originalArg){
          ...
}];

Что вам нужно сделать, это

  1. objc_allocateClassPair против собственного класса self, чтобы создать новый временный класс
  2. Превратить блок в указатель на функцию, например, используя это или это
  3. method_setImplementation для установки новой реализации во временный класс
  4. используйте от object_setClass до self, чтобы установить новый временный класс
  5. Я не понял, как предоставить super блоку: p

Считается, что это в основном то, как KVO делает Apple, см., Например. это обсуждение.

Чтение Справочник по времени выполнения .

2 голосов
/ 02 июня 2011

В Java у вас есть анонимный подкласс. Это невозможно в Objective-C (ну, в некотором роде, но вам придется делать некоторые довольно сложные искажения с библиотекой времени выполнения Obj-C).

Но Objective-C с iOS 4 или OS X 10.6 имеет «блоки», для чего и нужен синтаксис ^{}. Это понятие Objective-C о замыкании . Это не поможет вам напрямую, если вызываемые вами API не поддерживают обратные вызовы блоков, но вы можете создавать классы-оболочки, которые используют блоки вместо подклассовых методов для обработки обратных вызовов.

Есть много ресурсов для изучения блоков в Objective-C.

...