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 放在那里。
我有一个用 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 放在那里。