2015-12-29 16 views
1

Я пытаюсь понять, как правильно swizzle использовать method_setImplementation(). До сих пор в Интернете я видел два преимущественно популярных способа метода swizzle, один раз использовал method_setImplementation(), а остальные levarages method_exchangeImplementation.Как правильно swizzle с method_setImplementation()?

При использовании swizling с использованием method_exchangeImplementation() вы можете попасть в проблему, когда целевой класс не реализует метод, который вы пытаетесь выполнить. Чтобы избежать проблем с классом-предшественником, реализующим этот метод, и некорректно swizzling, сначала добавьте реализацию в свой целевой класс, а затем замените swizzledMethod IMP на свой метод классов-предков, чтобы привести в порядок. Это все имеет смысл для меня ...

Мой вопрос: как мы справляемся с тем же вышеприведенным случаем, когда swizzling с method_setImplementation? Разве мы не должны справляться с этим делом (интуитивно я чувствую себя так, как мы)? Если нам нужно обработать приведенный выше пример кода примера, это мне очень поможет, потому что я потерял его, как с этим справиться.

ответ

2

При выполнении бесплатных функций (ака регулярных функций) необходимо учитывать фактическую подпись метода, которую генерирует компилятор Objective-C, и тот факт, что IMP - это просто указатель на функцию, объявленный как это:

typedef id (*IMP)(id, SEL, ...); 

Если у вас есть метод, названный doSomethingWithObject:afterDelay:, который выглядит как этот

- (void)doSomethingWithObject:(id)object afterDelay:(NSTimeInterval)delay 

соответствующей функции C, что ген компилятор ставок (см Wikipedia больше о названии коверкая в Objective-C):

void _i_MyClass_doSometingWithObject_afterDelay(id self, SEL _cmd, id object, NSTimeInterval delay) 

так, если вы хотите обменять его, то вам необходимо создать подобный метод и передать указатель на него:

void swizzledDoSometingWithObjectAfterDelay(id self, SEL _cmd, id object, NSTimeInterval delay) { 
    // custom implementation 
} 

// .... 
method_setImplementation(method, (IMP)swizzledDoSometingWithObjectAfterDelay); 

Если метод, который вы хотите выполнить swizzle, может быть объявлен в классе предков, и вы хотите его использовать только для интересующего вас дочернего класса, вы можете использовать class_replaceMethod(), который либо добавляет, либо заменяет метод, и это влияет только на целевой класс:

SEL selector = @selector(doSomethingWithObject:afterDelay:); 
IMP newImp = (IMP)swizzledDoSometingWithObjectAfterDelay 
Method method = class_getClassMethod([MyClass class], selector); 
const char * encoding = method_getTypeEncoding(method); 
class_replaceMethod([MyClass class], selector, newIMP, encoding) 
+0

Спасибо за комментарий. Я считаю, что я понимаю логистику того, как подшучивать со свободными функциями, частью, о которой я особенно спрашиваю, является то, как обрабатывать случаи родословной, когда целевой класс не реализует эту функцию, а суперкласс. При swizzling через method_exchangeImplementation существует определенный способ справиться с этим, и я спрашиваю, есть ли какой-то аналогный способ справиться с этим при переходе через method_setImplementation. Я сломаю его в своем вопросе, если вы дадите ему прочитать. Если его неясно, пожалуйста, дайте мне знать, я могу попробовать подробнее ... – AyBayBay

+0

@AyBayBay Я обновил ответ, дайте мне знать, если последняя часть уточнит ваш вопрос. – Cristik

+0

спасибо! Я на самом деле не решил его предложить, но я считаю, что ваше предложение тоже должно работать! – AyBayBay