Метод swizzled Objective-C не получает аргументы

Я разрабатываю приложение, которое должно выполнять некоторые swizzling. Я использую метод -(void)m1:(CMAcceleration)a; с другим, который я предоставляю.

-(void)newM(id self, SEL _cmd, ...){
va_list args;
va_start(args, _cmd);
//...
NSInteger returnValue=((NSInteger(*)(id,SEL,...))origImp)(self,_cmd,args);
va_end(args);
}

Для того, чтобы его проглотить, я использую:

origImp=method_setImplementation(method, newImp);

Затем я обычно называю это как [ClassInstance m1:a]; Дело в том, что аргументы кажутся заполненными мусором, когда я ожидал структуру, подобную {name=type...}, как описано в здесь. Мне нужно передать аргументы исходной реализации после выполнения какой-либо операции, например NSLog.

При поиске в Интернете кажется, что это проблема, связанная с симулятором, но я не уверен, и у меня нет доступа к устройству, чтобы подтвердить это.

Я делаю что-то не так или есть способ это исправить?


person Leonardo Marques    schedule 13.12.2015    source источник
comment
Что, вам кажется, аргументы наполнены мусором? Покажите код, который вы использовали для определения этого. Что значит, вы ожидали такую ​​структуру, как {name=type...}? Покажите код того, как вы ожидали, что сможете использовать аргументы, как вы ожидали, что он будет вести себя, и как он ведет себя на самом деле. Также покажите пример вызова метода.   -  person Ken Thomases    schedule 14.12.2015
comment
@KenThomases Я отредактировал это, надеюсь, это поможет   -  person Leonardo Marques    schedule 14.12.2015


Ответы (1)


Вы делаете это очень неправильно.

Подпись метода должна совпадать, т.е. -(void)newM:(CMAcceleration)a;

а также

Method method = class_getInstanceMethod([SomeClass class],@selector(newM:));
IMP newImp = method_getImplementation(method);
origImp=method_setImplementation(method, newImp);

Другой способ - сделать функцию C

void newM(id self, SEL _cmd, CMAcceleration a) {

}

origImp=method_setImplementation(method, (IMP)newM);
person Bryan Chen    schedule 13.12.2015
comment
Нет ли более универсального способа сделать это? Я бы хотел, чтобы моя реализация метода newM была объединена в самые разные методы. - person Leonardo Marques; 14.12.2015
comment
Нет, если эти методы имеют разные подписи. Если только вы не хотите выполнить какую-то низкоуровневую работу (сборку) для создания функции, которая правильно принимает любое количество аргументов. (Вам нужно соблюдать модификаторы ARC, чтобы избежать сбоя) - person Bryan Chen; 14.12.2015
comment
Что вы имеете в виду под правильно принять любое количество аргументов? Разве это не то, что представляют собой функции с переменным аргументом? - person Leonardo Marques; 14.12.2015
comment
@LeonardoMarques Нет. Это не так. В зависимости от архитектуры и платформы void m(...), void m(double) и void(id) могут иметь разные соглашения о вызовах. Аргументы могут передаваться по стеку, по регистру, по регистру fp, вы должны обрабатывать все разные случаи. Без ассемблерного кода это сделать невозможно. - person Bryan Chen; 14.12.2015
comment
Разве все методы не получают objc_msgSend одинаково? Может быть, это может быть обходным путем? - person Leonardo Marques; 14.12.2015
comment
@LeonardoMarques Да и нет. Вам нужно сначала привести objc_msgSend, чтобы получить правильный тип (компиляция делает это автоматически). Прочитайте этот ответ для получения дополнительной информации: stackoverflow.com/a/2573949/642626 - person Bryan Chen; 14.12.2015