使用setReturnValue从NSInvocation返回NSString

5

当我将NSInvocation的返回值设置为NSString时,调用者接收到了一个NSCFString。

在我的情况下,我正在模拟从单元测试中包含的文件中提取捆绑路径:

[[[_bundlePartial stub] andDo:^(NSInvocation *invocation) {
    NSString* resourceName = [invocation getArgumentAtIndexAsObject:2];
    NSString* type = [invocation getArgumentAtIndexAsObject:3];
    NSString* path = [[NSBundle bundleForClass:self.class] pathForResource:resourceName ofType:type];
    if (!path)
    {
        path = [_bundleOriginal pathForResource:resourceName ofType:type];
    }
    [invocation setReturnValue:(void*)path];
}] pathForResource:OCMOCK_ANY ofType:OCMOCK_ANY];

我这样称呼它:

NSString* jsonPathInBundle = [[NSBundle mainBundle] pathForResource:self.fileName ofType:self.fileExtension];

不幸的是,我得到了一个NSCFString。这是有道理的,因为我的NSString是由NSCFString支持的,但当我失去桥接时,我不能再在对象上调用NSString实例方法。有没有一种方法可以将值作为NSString返回?


NSString是一个类簇。所有字符串都是某个子类的实例。你不能在实例上调用哪个方法? - Martin R
@MartinR 在下一行会失败:NSString* json = [NSString stringWithContentsOfFile:jsonPathInBundle encoding:NSUTF8StringEncoding error:error];,因为stringWithContentsOfFile:encoding:error:不是NSCFString上的方法。 - Ben Flynn
1个回答

9
在检查了OCMock代码之后,我发现了自己的问题。实际上这只是一个拼写错误,但它足够微妙,以至于我认为删除这个问题并不值得。
更改为:
[invocation setReturnValue:(void*)path];

To:

[invocation setReturnValue:&path];

我的原始写法破坏了一层抽象,因为NSString被当作地址来处理,而不是使用它的实际地址。


1
是的 - NSInvocation 总是需要指向原始值的指针,但您直接传递了该值。它将取消引用指针,获取“isa”值(Class 对象),并将其视为 NSString 实例,最有可能的情况。其次,如果使用 ARC,请在“type”和“resourceName”变量上使用 __unsafe_unretained(用于从 NSInvocation 中提取对象),否则您很可能会在以后遇到崩溃,因为 ARC 将过度释放这些对象。 - Carl Lindberg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接