情况是这样的:
在异步函数中,我捕获了一个弱自我。
__block auto weakSelf = self;
然后,在街区内,我捕捉到了一个强大的自我。
[_someIvar someAsyncMethod:^{
__strong auto strongSelf = weakSelf;
}];
但是,如果strongSelf为零,我会做一些错误处理和报告。
if (!strongSelf) {
_NotifyDelegate(someDeallocationError); // C
}
整件事:
__block auto weakSelf = self;
[_someIvar someAsyncMethod:^{
__strong auto strongSelf = weakSelf;
if (!strongSelf) {
// How can I trigger this line?
_NotifyDelegate(someDeallocationError); // C
}
}
}];
这都是遗留代码,我正在使用 OCMock 添加单元测试。如何在运行时使 strongSelf nil 并触发该委托通知?
据我所知,您尚未指定任何类名,但假设您有:
@interface SomeClass
…
@end
…
@interface IvarClass
- (void) someAsyncMethod:(void(^)(void))block;
@end
…
@implementation SomeClass
{
IvarClass* _someIvar;
}
…
- (void)someMethod
{
__block auto weakSelf = self;
[_someIvar someAsyncMethod:^{
__strong auto strongSelf = weakSelf;
if (!strongSelf) {
// How can I trigger this line?
_NotifyDelegate(someDeallocationError); // C
}
}];
}
@end
在这种情况下,我会用一个StubIvarClassDelayedAsync
对IvarClass
进行子类化,您可以在其中覆盖- (void) someAsyncMethod:
以便块简单地存储在 ivar 中。然后,沿着调用块的- (void)completeAsyncMethod
行在其上实现另一个方法。
您需要使用此StubIvarClassDelayedAsync
的实例作为测试中的_someIvar
- 或者您可以通过SomeClass
上的现有 API 直接注入它,否则您可能需要子类化SomeClass
以更改创建生产实例的位置。
在测试方法中将它们放在一起:在@autoreleasepool
块中,创建SomeClass
(或其存根子类)的实例,使用StubIvarClassDelayedAsync
的实例准备它,然后调用someMethod
。这反过来应该会导致调用someAsyncMethod:
的覆盖版本,该版本存储块引用。(您可以断言调用该方法是为了良好的度量。 在测试中nil
出SomeClass
指针,并关闭池块以删除任何最后的引用。你可能想断言dealloc
在你的SomeClass instance
上被调用,如果使用虚拟子类,你可以很容易地做到这一点。但是,请确保保留指向StubIvarClassDelayedAsync
实例的指针。最后,在该存根实例上调用completeAsyncMethod
,这应该会导致块采用错误处理分支。
如果您提供的不仅仅是未命名的片段,我会更具体地介绍代码示例,如果您在各自的方法中在这些片段之前或之后有代码,那么可能需要首先考虑或重构。实名制也很有用。