首页 > 解决方案 > 超类的init方法为NS_UNAVAILABLE时如何初始化子类

问题描述

我正在尝试为objective-c 类编写测试。我要测试的类是MyClass,它看起来像这样:

@interface MyClass : NSObject
- (void)dispatchEvent:(IMAAdEvent *)event;
@end

为了测试这个dispatchEvent方法,我需要传入一个IMAAdEvent. 该类IMAAdEvent来自谷歌的图书馆GoogleAds-IMA-iOS-SDK

不幸的是,我不能调用init这个类,因为 init 方法被标记为NS_UNAVAILABLE. 在 XCode 中,我收到一个反映这一点的错误:

'init' 不可用

理想情况下,我想制作自己的这样的模拟子类IMAAdEvent。有什么方法可以在不调用超类上不可用的 init 方法的情况下初始化我的子类?:

@interface MockImaAdEvent : IMAAdEvent
@end

@implementation MockImaAdEvent
- (id)init {
  // is there something I can do here so that I return an instances
  // of the subclass without calling [super init]?
}
@end

标签: objective-cunit-testing

解决方案


从 Xcode 12.5 开始,Swift 不再能够使用以前的解决方案。编译器已开始为添加了新函数init() is unavailable的代码行返回错误。initXcode 12.5 发行说明指出以下内容:

Clang 现在从 -init 方法上的可用性注释推断 +new 的可用性。由于 +new 调用 [[Foo alloc] init],所以 +new 不可用,除非 +init 可用。

尽管有此发行说明,但仍有一个有效的解决方法。通过在 Objective-C 中编写模拟类并使用桥接头将其引入 Swift,模拟类仍然可以调用super.new以获取父类的新实例(然后从那里自定义子类)。

这是一个例子:

@interface MockInAppMessagingCampaignInfo ()

@property (strong, nonatomic) NSString *campaignNameValue;

@end

@implementation MockInAppMessagingCampaignInfo

+ (id)newWithCampaignName:(NSString *)campaignName {
    MockInAppMessagingCampaignInfo *newObject = super.new;
    newObject.campaignNameValue = campaignName;
    return newObject;
}

- (NSString *)campaignName {
    self.campaignNameWasCalled = YES;
    return self.campaignNameValue ?: @"";
}

@end

推荐阅读