在我们的测试框架中(基于Kiwi,而Kiwi又基于XCTest),我们使用NSHipster here上描述的“swizzling on load”技术来切换一些东西与嘲笑负载。直到我们升级到XCode 7之前它一直运行良好,现在不知何故+load
方法被调用两次。据我了解,不管发生什么都不应该发生?XCode 7 XCTest(Kiwi)+加载类方法调用两次
这里的第一个+负载调用的堆栈跟踪(发生main
前):
Foo`+[FooManager(self=FooManager, _cmd="load") load] + 149 at FooExtensions.mm:152
libobjc.A.dylib`call_load_methods + 292
libobjc.A.dylib`load_images + 129
...
dyld`dyld::useSimulatorDyld(int, macho_header const*, char const*, int, char const**, char const**, char const**, unsigned long*) + 1053
dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*) + 202
dyld`dyldbootstrap::start(macho_header const*, int, char const**, long, macho_header const*, unsigned long*) + 428
dyld`_dyld_start + 71
这是第二次调用堆栈的样子:
FooTests`+[FooManager(self=FooManager, _cmd="load") load] + 149 at FooExtensions.mm:152
ibobjc.A.dylib`call_load_methods + 292
ibobjc.A.dylib`load_images + 129
libdyld.dylib`dlopen + 70
CoreFoundation`_CFBundleDlfcnLoadBundle + 185
CoreFoundation`_CFBundleLoadExecutableAndReturnError + 336
Foundation`-[NSBundle loadAndReturnError:] + 641
XCTest`_XCTestMain + 542
IDEBundleInjection`____XCBundleInjection_block_invoke_2 + 20
CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 16
CoreFoundation`__CFRunLoopDoBlocks + 195
CoreFoundation`__CFRunLoopRun + 1016
CoreFoundation`CFRunLoopRunSpecific + 470
CoreFoundation`CFRunLoopRunInMode + 123
GraphicsServices`GSEventRunModal + 192
GraphicsServices`GSEventRun + 104
UIKit`UIApplicationMain + 160
Foo`UIApplicationMain(argc=<unavailable>, argv=<unavailable>, principalClassName=0x00000000, [email protected]"AppDelegate") + 227 at ApplicationHooks.m:56
Foo`main(argc=5, argv=0xbfff7778) + 146 at main.mm:15
libdyld.dylib`start + 1
它看起来像动态loader最初按预期调用+load
方法,但是然后XCTest运行时再次调用它们。
事情是,即使dispatch_once
不起作用,因为静态变量似乎没有正确启动,因此dispatch_once_t
令牌在+load
调用之间变化!唯一有效的工作是创建一个C++类并将dispatch_once
调用委托给它(对于dispatch_once_t
使用适当的C++静态变量)。
编辑 - 我很确定这个+load
order change是相关的,但我不知道如何改变顺序会导致它运行两次。
EDIT2 - 看来,这种行为是不是新的。从在related blog post评论:
如果您运行的是注入到一个应用程序的测试包,并 无论是应用和测试包链接到同一个某文件,在任何负载 方法.a文件将被触发两次。
很确定您的包正在被加载的调用之间卸载。尝试创建一个'__attribute __((析构函数))'函数,看看是否如此。如果我的理论是正确的,你可以通过让测试目标不链接到具有类别的框架,或者通过使用'dlopen'和朋友的运行时链接来解决它。 –
感谢您的快速响应!我实现了构造函数和析构函数,如下所述:http://stackoverflow.com/q/2053029/67824并在它们中的每一个中引发了NSLog。有趣的是,捆绑包从未卸载过,但它确实加载了两次。鉴于此,我还应该尝试一下你的解决方法吗?如果是这样,我的测试目标需要具有该类别的库(就像我说过我们使用'+ load'来模拟一些东西),所以我想我应该去'dlopen'路线? –
顺便说一句,这个软件包加载两次肯定是件坏事?否则,也许我可以放弃在应用程序委托('didFinishLaunchingWithOptions')中进行swizzling? –