当从 UIStoryboard 实例化 ViewController 时,isMemberOfClass 返回 no

Posted

技术标签:

【中文标题】当从 UIStoryboard 实例化 ViewController 时,isMemberOfClass 返回 no【英文标题】:isMemberOfClass returns no when ViewController is instantiated from UIStoryboard 【发布时间】:2012-07-26 17:59:54 【问题描述】:

我有一个 OCUnit 测试类:PatientTestViewControllerTests。下面是界面:

@interface PatientTestViewControllerTests : SenTestCase

@property (nonatomic, strong) PatientTestViewController *testController;

@end

和设置:

- (void) setUp
    
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Testing" bundle:nil];
    self.testController = [storyboard instantiateInitialViewController];

“测试”故事板是我的应用程序中唯一的故事板,并被设置为应用程序的主故事板。 PatientTestViewController 被设置为情节提要的唯一视图控制器。

我的测试班有一个测试:

- (void) testInitialTestingStoryboardViewIsPatientTest

    STAssertTrue([self.testController isMemberOfClass:[PatientTestViewController class]], @"Instead of the %@, we have %@",[PatientTestViewController class], [self.testController class]);

此测试失败并显示以下日志消息:

错误:-[PatientTestViewControllerTests testInitialTestingStoryboardViewIsPatientTest]:“[self.testController isMemberOfClass:[PatientTestViewController class]]”应该为真。我们使用 PatientTestViewController

代替 PatientTestViewController

这怎么可能?自从

[self.testController isMemberOfClass:[PatientTestViewController class]]

显然是假的,测试日志怎么能说两者都是

[self.testController class][PatientTestViewController class]

看起来一样吗?

附加信息:

在测试中使用[self.testController isKindOfClass:[PatientTestViewController class]] 也会失败

使用[self.testController class] == [PatientTestViewController class] 也会失败。

使用[self.testController isKindOfClass:[UIViewController class]] PASSES。

使用 [self.testController isMemberOfClass:[UIViewController class]] 失败。

【问题讨论】:

出于好奇,NSLog(@"Expected address: %p, actual: %p",[PatientTestViewController class], [self.testController class]); 长什么样子? @JoshCaswell 啊哈。有趣的问题!和一个有趣的答案。 “预期地址:0x679fa48,实际:0x59bc” 那么……这是什么意思?显然它们是不同的内存地址......但是 isMemberOfClass 测试的对象是什么?是严格的对象相等吗,比如'=='? @JoshCaswell 有趣的是,如果我使用标准的 alloc/init 在 setUp 中实例化 testController 对象,则测试通过没有问题,并且两个地址相同。那么为什么[UIStoryboard instantiateInitialViewController] 会返回不同的东西......它有什么不同呢? 我不确定isMemberOfClass: 如何在内部检查相等性。我有点怀疑 UIStoryboard 出于某种原因创建了一个虚拟替代类。可能是某种懒惰。怎么样:如果你给testController发消息,然后isMemberOfClass:isKindOfClass:,然后打印地址会怎样? 我想你可能会在这里做点什么。向testController 发送消息并没有改变任何东西(地址仍然存在相同的差异)。但是,我创建了一个新项目来复制问题,但我无法复制它。这两个项目之间唯一真正的区别是我在摆弄我原来的故事板。我一定做了……什么。 【参考方案1】:

问题可能是您的视图控制器的 .m 文件包含在两个目标中,即应用程序和测试包中。 ocunit(以及 Kiwi 等衍生产品)使用测试工具,使应用程序中包含的类可用于测试,而无需显式包含它们的实现。

同时包含这两个副本为您提供了同一类的两个副本,这就是为什么它们具有相同的描述但内存地址不同的原因。

【讨论】:

目瞪口呆。就是这样。从测试目标和 blammo 中删除了 .m 文件。一切都会过去。我习惯了 GHUnit,你必须在两个目标中都包含 .m 文件。 谢谢 - 你刚刚解决了 HOURS 令人头疼和讨厌的创建 NSStrings-from-class-names 变通办法! 拯救我的一天!!!谢谢你指出这一点。我在我的测试项目中添加了我的模型文件,但不需要它。 要回答这个问题,从测试目标中删除源文件后,您可能需要set up the symbols to unhide themselves。【参考方案2】:

您通常需要isKindOfClass: 而不是isMemberOfClass:。不同之处在于,如果接收者是相关类的子类的成员,isKindOfClass: 将返回 YES,而 isMemberOfClass: 在相同情况下将返回 NO

您也可以使用[self.testController class] == [PatientTestViewController class] 直接比较类。

【讨论】:

感谢您的回复。我希望测试是具体的,这就是我使用 isMemberOfClass 的原因。故事板的初始视图应该完全是 PatientTestViewController,而不是子类。但是,我确实也尝试过 isKindOfClass,只是为了确定。没有骰子。我喜欢 '==' 测试的想法,但它也不起作用。 :( 我将在问题中添加一些其他信息以及我尝试过的其他信息。

以上是关于当从 UIStoryboard 实例化 ViewController 时,isMemberOfClass 返回 no的主要内容,如果未能解决你的问题,请参考以下文章

UIViewController 扩展从情节提要中实例化

如何实例化第二个 ViewController 并停止第一个 ViewController 的方法

如何删除最后一个实例化的ViewController,最后一个TableViewController变为活动状态

当从其父视图中删除第二个 ViewController 时,FirstViewController 不起作用

幽灵视图控制器

是否可以在不同的 UIStoryBoard 的 UIViewController 中使用 UIStoryBoard?