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

Posted

技术标签:

【中文标题】AppDelegate 类不适用于 iOS Swift 应用程序中的 Obj-C 嵌入式库【英文标题】:AppDelegate Class not Available to Obj-C Embedded Library in iOS Swift App 【发布时间】:2017-02-09 18:31:06 【问题描述】:

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

下面是库中的代码:

(注意:这个方法是从 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 应用程序中运行时,appDelegate 为 null,并且 swizzle 失败。

两种语言之间的应用程序委托的初始化顺序有什么不同吗?我还缺少什么吗?

【问题讨论】:

这在 Obj-c 应用程序中是如何工作的? +load 应该在 main 之前调用,main 是 UIApplication 被创建和初始化的地方。 【参考方案1】:

我不确定这在 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 是可取的,因为您不知道这是否会覆盖在类本身上定义的某些 +load 方法。我相信在这种情况下,未定义哪个被称为?我得检查一下。更好的解决方案可能是创建您自己的 UIResponder 派生类并将您的 +load shim 放在那里。

【讨论】:

我喜欢这个解决方案!我实现了观察者,它工作得很好。谢谢!【参考方案2】:

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

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

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

【讨论】:

我尝试了这种技术,但从未在 UIResponder 类上调用初始化方法。我想是因为我们只在那里使用静态方法吗?无论如何,当我使用它时,我的所有代码都不会被调用。

以上是关于AppDelegate 类不适用于 iOS Swift 应用程序中的 Obj-C 嵌入式库的主要内容,如果未能解决你的问题,请参考以下文章

iOS 应用程序:Firebase 动态链接不适用于最新的 Pod 文件

PKAddPassButton 不适用于 iOS 9

iOS 框架不适用于模拟器

CATiledLayer 不适用于我的 iOS5 项目

钥匙串类不适用于 iPhone 4s/5 和 iPad

如何通过 AppDelegate 升级使功能可用于大于 8 的 iOS