gpt4 book ai didi

ios - 调整 AppDelegate 方法

转载 作者:行者123 更新时间:2023-11-29 00:09:21 24 4
gpt4 key购买 nike

我正在开发需要获取应用程序生命周期事件的框架。我正在尝试使用 NotificationCenter 它在框架下失败了。所以我决定使用 obj c 运行时实现 Method Swizzling。问题是以下代码在 Emulator 中正常工作。当我运行设备时,它失败了。

好消息是扩展方法被调用,当调用原始方法时,这会失败并显示消息

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);
}

我在我的示例项目中使用通用框架构建来使用这个框架。请告诉我这有什么问题。

最佳答案

Kindly let me know whats wrong with this.

我无法运行您的代码(它是不完整的),但以下可能会导致您的问题。

首先 applicationWillResignActive 的声明是:

- (void)applicationWillResignActive:(UIApplication *)application;

但是在您的 extendedApplicationWillResignActive 函数中,您已将 UIApplication * 更改为 va_list,这是错误的。在某些情况下它可能会起作用,看起来它可能在模拟器中对您有用,但在某些情况下它会爆炸,就像您在您的设备上发生的那样(请注意,此处模拟器运行 x86 代码,设备ARM代码)。

这里很明显的问题是为什么要更改参数的类型?

其次,您正在绕过编写方法并直接使用(错误类型的)C 函数进行调配。虽然本身并没有错,但它可能对您没有帮助。

第三,您尝试添加一个方法:

- (void)extendedApplicationWillResignActive:

在没有任何检查这样的方法是否已经存在的情况下进入一个类。这充其量是不明智的,您的框架如何知道使用它的应用程序没有定义这样的方法?可能性可能很小,但它大于零,并且是不必要的风险。那就是说这对您的情况可能不是问题(因为您编写了正在调配的类,所以知道没有这样的现有方法)。

最后,您已经硬连线了您正在调配的类的名称 AppDelegate。应用程序委托(delegate)可以有不同的名称。您的 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

关于ios - 调整 AppDelegate 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47029511/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com