我正在使用Framework,需要获取应用程序生命周期事件。我尝试使用 NotificationCenter ,它在框架下失败了。所以我决定使用obj c运行时实现 Method Swizzling 。问题是以下代码在模拟器中正常工作。当我运行设备时,它会失败。
好的方法是调用Extended方法,当调用原始方法时,这会因消息
而失败Thread 1: EXC_BAD_ACCESS (code=1, address=0x20)
这是我的代码
IMP originalImplementation;
+ (instancetype)initWith:(NSString *)bundleIdentifier{
Demo *instance = [[Demo alloc] init];
[instance swizzlingLifeCycleMethods];
return instance;
}
- (void)swizzlingLifeCycleMethods{
//Prepare the injected class name to be injecting
Class originalClass = NSClassFromString(@"AppDelegate");
//Prepare the methods to swizzling
SEL originalWillResignAction = @selector(applicationWillResignActive:);
SEL extendedWillResignActive = NSSelectorFromString(@"extendedApplicationWillResignActive");
//Get original method and method encoding
originalResignMethod = class_getInstanceMethod(originalClass, originalWillResignAction);
originalImplementation = method_getImplementation(originalResignMethod);
const char *originalResignMethodEncoding = method_getTypeEncoding(originalResignMethod);
//Add swizzling method into targetted class
class_addMethod(originalClass, extendedWillResignActive, (IMP)extendedApplicationWillResignActive, originalResignMethodEncoding);
//Swizzling the methods
Method extendedResignMethod = class_getInstanceMethod(originalClass, extendedWillResignActive);
method_exchangeImplementations(originalResignMethod, extendedResignMethod);
}
//Called at the time of user enters into background
void extendedApplicationWillResignActive(id self, SEL _cmd, va_list args1)
{
//Implement our logic here
//Call the original function after our stuff done
((void(*)(id, SEL, ...))originalImplementation)(self, _cmd, args1);
}
我在我的示例项目中使用Universal Framework构建来使用此框架。请告诉我这是错误的。
答案 0 :(得分:1)
请告诉我这是错误的。
我无法运行您的代码(它不完整),但以下内容可能会对您的问题有所帮助。
首先,applicationWillResignActive
的声明是:
- (void)applicationWillResignActive:(UIApplication *)application;
但是,在extendedApplicationWillResignActive
功能中,您已将UIApplication *
更改为va_list
,这是错误的。有些情况下它可能会起作用,它似乎可能在你的模拟器中,但有时会爆炸,就像你的设备上发生的那样(注意这里模拟器运行x86代码,设备ARM代码。)
这里显而易见的问题是你为什么要改变论证的类型?
其次,您绕过编写方法并直接使用(错误键入的)C函数进行调整。虽然没有错误本身,但它可能无法帮助你。
第三,您正在尝试添加方法:
- (void)extendedApplicationWillResignActive:
到一个类,没有检查这样的方法是否已经存在。这是不明智的,你的框架如何知道使用它的应用程序没有定义这样的方法?可能性可能很小,但大于零,并且是不必要的风险。那说这可能不是你的问题(因为你写的是你正在调整的课程,所以知道没有这样的现有方法)。
最后,您已经将您正在调配的班级名称AppDelegate
硬连线。应用程序委托可以使用不同的名称。您的initWith:
方法会使用当前未使用的参数bundleIdentifier
,因此我认为这表明您打算解决此问题。
让我们看看我们是否可以帮助您解决这个问题。你在这里尝试做的是跨类调配。为此,您可以:
以下是包含这些更改的代码。 此代码只是在线复制和编辑,尚未运行,预计错误,仅作为大纲。
@implementation Demo
{
// define a typedef for the target method's implementation function
typedef void (*OriginalImpType)(id self, SEL selector, UIApplication *application);
// declare this static as it is private to this class
static OriginalImpType originalImplementation;
+ (instancetype)initWith:(NSString *)bundleIdentifier{
Demo *instance = [[Demo alloc] init];
[instance swizzlingLifeCycleMethods:bundleIdentifier];
return instance;
}
- (void)swizzlingLifeCycleMethods:(NSString *)bundleIdentifier
{
// Get the class for the application delegate
Class originalClass = ... however you plan to do this using bundleIdentifier ...;
// Get the swizzling class
Class demoClass = [Demo class];
// Prepare the methods to swizzling
SEL originalWillResignAction = @selector(applicationWillResignActive:);
SEL extendedWillResignActive = @selector(extendedApplicationWillResignActive:);
// Get original method and save it
Method originalResignMethod = class_getInstanceMethod(originalClass, originalWillResignAction);
originalImplementation = (OriginalImpType)method_getImplementation(originalResignMethod);
// Swizzling the method
Method extendedResignMethod = class_getInstanceMethod(demoClass, extendedWillResignActive);
method_setImplementation(originalResignMethod, method_getImplementation(extendedResignMethod));
}
// Called at the time of user enters into background
- (void) extendedApplicationWillResignActive:(UIApplication *)application
{
//Implement our logic here
//Call the original function after our stuff done
originalImplementation(self, _cmd, application);
}
} // end of @implementation Demo
HTH