Метод Objective-c IOS arm64 не может вызвать исходный метод

Я использую стандартный метод swizzling на устройствах ARMv7 IOS, и он отлично работает для меня.

Но когда я компилирую свой код для arm64 - он не может вызвать исходный метод из нового метода

Основная цель моей махинации - использовать параметр из внутреннего метода моего приложения в другом методе.

У меня есть оригинальный метод -(void)insertdata:(id)text, и я хочу изменить его на -(void)patchedCall:(id)text и вызвать оригинальный метод в новом методе.

Код:

static IMP sOriginalImp = NULL;

@interface TextOverrides: NSObject
+(void)load;
-(void)patchedinsert:(id)text;
@end

@implementation TextOverrides

+(void)load
{
    //Get Implementation of original method

    Class originalClass = NSClassFromString(@"DataViewController");
    Method originalMeth = class_getInstanceMethod(originalClass, @selector(insertdata:));

    //Save original method implementation
    sOriginalImp = method_getImplementation(originalMeth);

    // Get implementation of replacement method
    Method replacementMeth = class_getInstanceMethod(NSClassFromString(@"TextOverrides"), @selector(patchedCall:));

    //Replace methods
    method_exchangeImplementations(originalMeth, replacementMeth);
}

-(void)patchedCall:(id)text
{
    @synchronized(self){
        //Call of original method that we save
        sOriginalImp(self, @selector(insertdata:), text);

        //Make our code for argument "text"
        printf("Here is data%s\n", [text UTF8String]);
    }
}

@end

Код не работает при вызове оригинального метода на архитектуре arm64:

//Call of original method that we save
sOriginalImp(self, @selector(insertdata:), text);

Как я могу улучшить свой код, чтобы он работал как на armv7, так и на arm64?


person Yakov    schedule 10.12.2014    source источник


Ответы (2)


С обсуждением на https://github.com/square/PonyDebugger/issues/84 Я думаю, суть в следующем: https://developer.apple.com/library/ios/documentation/General/Conceptual/CocoaTouch64BitGuide/ConvertingYourAppto64-Bit/ConvertingYourAppto64-Bit.html#//apple_ref/doc/uid/TP40013501-CH3-SW22 и тот факт, что IMP определена как функция с переменным числом аргументов, и вы вызываете ее с фиксированными аргументами. В моем случае приведение указателя функции к реальной подписи устранило сбой. Я верю в ваш случай, что-то вроде

//Call of original method that we save
((void(*)(id, SEL, id))ssOriginalImp)(self, @selector(insertdata:), text);

может исправить сбой.

person ashcatch    schedule 12.02.2015

Я не думаю, что где-то указан порядок загрузки всех классов. Так что может быть, что класс TextOverrides загружается раньше DataViewController на arm64, но не на armv7. См. https://www.mikeash.com/pyblog/friday-qa-2009-05-22-objective-c-class-loading-and-initialization.html

Чтобы сделать его стабильным, вы должны использовать методы только в категории +метод загрузки. Например:

@interface DataViewController (TextOverrides)
+(void)load;
-(void)patchedinsert:(id)text;
@end

@implementation DataViewController (TextOverrides)

+(void)load
{
    // swizzle here
}
...
person Mats    schedule 10.12.2014
comment
Я использую этот код как динамическую библиотеку, и DataViewController не может использоваться таким образом. Я отлаживаю код в рантайме - методы класса DataViewController загружаются раньше и swizzling работают - методы меняются и если мы не вызываем исходный метод - все работает нормально. Но когда мы его вызываем - он не может найти селектор. - person Yakov; 11.12.2014