Я предполагаю, что вы не контролируете реализацию класса, чей метод вы хотите перехватить, и поэтому изменение API, как предполагает @Conrad Shultz, невозможно. На ум приходит несколько других подходов.
Первый - это метод Swizzling. Это работает так: вы добавляете метод с той же сигнатурой в класс, используя категорию, затем вы меняете реализации метода, который вы хотите перехватить, и метода, который вы добавили. Метод, который вы добавите, будет вызывать любые хуки, которые вы хотите, до и / или после вызова самого себя. Поскольку вы меняете реализации, вызов «себя» фактически вызывает оригинальный метод. Есть много хороших объяснений метода метания там. Вот один.
Другой вариант может заключаться в том, чтобы обернуть объект в NSProxy и пропустить вызовы, используя -forwardInvocation
. Опять же, есть много ресурсов, подробно объясняющих прокси и переадресацию вызовов, поэтому я не буду перефразировать это здесь. Вот один из них. Этот подход ограничен тем, что у вас должен быть необходимый доступ к свопу в прокси для реального объекта. Если объект создается в частном порядке внутри какого-либо API, такой подход не будет полезен.
Другой подход - делать то, что делает КВО. Наблюдение значения ключа работает путем создания подкласса класса во время выполнения, а затем выполнения то, что называется isa
- колебание, чтобы изменить класс существующего экземпляра на новый динамический подкласс. Нет причины, по которой вы не могли бы создать сгенерированный во время выполнения подкласс класса, метод экземпляра которого вы хотите перехватить, а затем заставить реализацию этого метода, сгенерированную во время выполнения, вызывать любые другие хуки до и / или после вызова суперкласса. (реальная) реализация метода. Это может позволить вам перехватывать более чем один метод более просто, но не будет простого способа перехвата произвольных методов с произвольными сигнатурами, потому что вы должны найти способ вызывать свои хуки без искажения стек, а затем направить в основную реализацию. Этот способ перехвата произвольных методов с произвольными сигнатурами, вероятно, потребует написания батутов в сборке и последующего вызова в реальной реализации, как это делает objc_msgSend. Вот хорошая статья о создании подклассов во время выполнения .
Для исторической перспективы: раньше также использовалась функция по имени poseAsClass, которая также позволяла бы это, но она была удалена, я думаю, со времен SnowLeopard-ish, так что, вероятно, это не стартер.
Любой из этих вариантов будет иметь последствия для производительности и все они будут чрезвычайно «умными». Я не говорю это, чтобы погладить себя по спине - я не придумал ничего из этого, только отрыгнул их. Но я заметил, что на протяжении многих лет, когда решение кажется чрезмерно «умным», это явный признак того, что я направляюсь к возможной катастрофе. Иными словами, если API, с которым вы работаете, не дает вам возможности перехватывать эти вызовы методов, это, вероятно, признак того, что вам следует подойти к проблеме с другой стороны. Но ваш пробег может меняться, очевидно.