AppDelegate Class 不适用于 iOS Swift 应用程序中的 Obj-C 嵌入式库

AppDelegate Class not Available to Obj-C Embedded Library in iOS Swift App

我有一个用 Objective C 编写的库,作为 Cocoapod 发布。该库所做的部分工作是对添加到的任何应用程序的 AppDelegate class 进行一些调整。当库被添加到一个简单的 Objective-C 应用程序(一个没有任何内容的单页应用程序)时,回调方法被适当地混合,每个人都很高兴。但是,当库被添加到类似的 Swift 应用程序时,调配失败,因为 AppDelegate 为 null(或 nil)。

下面是库中的代码:

(注意:此方法是从 UIResponder 的 load: 方法中调用的。)

UIResponder+MyCustomMethods.m

/**
 *  This class swizzles the methods needed to observe protocol methods
 */
@implementation UIResponder (WTAutomatics)

...

+ (void)swizzleAppDelegate:(SEL)original with:(SEL)replacement forProtocol:(Protocol *)protocol
{
    id appDel = [[UIApplication sharedApplication] delegate];
    Class appDelegate = [appDel class];
    // Alternatively, we can do this. Both work the same.
    // Class appDelegate = [[[UIApplication sharedApplication] delegate] class];

    NSLog(@"Starting swizzle: %@", NSStringFromSelector(original));    
    if (!appDelegate) {
        WTLog(@"Failed to swizzle because appDelegate is null.");
        return;
    }

    if (class_conformsToProtocol(appDelegate, protocol)) {
        // Do the method swizzling
        ...
    }
}

在上面的代码中,appDelegate 的值是有效的,并且 swizzling 在任何 Objective C 应用程序中都有效。但是,当 Swift app 中的 运行 并且 swizzle 失败时,appDelegate 为 null。

两种语言在应用程序委托的初始化顺序上有什么不同吗?还有什么我想念的吗?

Apple 文档:+load 每当将 class 或类别添加到 Objective-C 运行时时调用;实现此方法以在加载时执行 class-specific 行为。

您的 AppDelegate 似乎尚未加载。尝试从另一个地方调用您的 swizzling。例如

+(void)initialize{
[self swizzle...];

}

我不确定这在 Obj-C 应用案例中对您有何帮助。在我的测试中,+load 在应用程序的 main() 方法之前被调用,这是创建和初始化 UIApplication 的地方。在我的测试中,以下两行均打印 (null):

@interface UIResponder (blah)
@end
@implementation UIResponder (blah)
+ (void) load
{
    NSLog( @"application: %@", [UIApplication sharedApplication] );
    NSLog( @"delegate:    %@", [[UIApplication sharedApplication] delegate] );
}
@end

这是一个可以满足您要求的版本:

@interface UIResponder (blah)
@end
@implementation UIResponder (blah)
+ (void) load
{
    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(didFinishLaunching:) name: UIApplicationDidFinishLaunchingNotification object: nil];

}
+ (void) didFinishLaunching: (NSNotification*) n
{
    NSLog( @"application: %@", [UIApplication sharedApplication] );
    NSLog( @"delegate:    %@", [[UIApplication sharedApplication] delegate] );
}
@end

此外,我认为在类别扩展中实现 +load 是不可取的,因为您不知道这是否会覆盖 class 本身定义的某些 +load 方法。我相信在这种情况下,它被称为哪个是不确定的?我得检查一下。更好的解决方案可能是创建您自己的 UIResponder-derived class 并将您的 +load shim 放在那里。