Objective c NSInvocation getReturnValue:在forwardInvocation:内部调用使返回的对象调用dealloc:

Objective c NSInvocation getReturnValue:在forwardInvocation:内部调用使返回的对象调用dealloc:,objective-c,nsinvocation,Objective C,Nsinvocation,这里有一个独立的test.m文件,我用它来测试行为 编译:clangtest.m-otest.app-fobjcarc-ObjC-frameworkfoundation。确保安装了Xcode命令行工具 #import <Foundation/Foundation.h> @protocol Protocol @optional - (id)objProxyMethod; @end @interface ReturnObject: NSObject @end @interfa

这里有一个独立的
test.m
文件,我用它来测试行为

编译:
clangtest.m-otest.app-fobjcarc-ObjC-frameworkfoundation
。确保安装了Xcode命令行工具

#import <Foundation/Foundation.h>

@protocol Protocol

@optional
- (id)objProxyMethod;

@end

@interface ReturnObject: NSObject

@end

@interface Test : NSObject <Protocol>

@end

@interface Proxy : NSObject <Protocol>

- (id)objProxyMethod;

@end

@implementation ReturnObject

- (void)dealloc {
    NSLog(@"ERROR:");
    NSLog(@"I'm getting deallocated!");
    NSLog(@"This shouldn't happen!");
}

- (NSString *)description {
    return @"Blank object!";
}

@end

@implementation Proxy

- (id)objProxyMethod {
    NSLog(@"in [Proxy objProxyMethod]!");
    return [[ReturnObject alloc] init];
}

@end

@implementation Test

- (void)forwardInvocation:(NSInvocation *)invocation {
    NSLog(@"Forwarded invocation!");
    Proxy *proxy = [[Proxy alloc] init];
    [invocation invokeWithTarget: proxy];
    NSUInteger length = [[invocation methodSignature] methodReturnLength];
    if (length == 8) {
        id result;
        [invocation getReturnValue:&result];
    }
}

@end

int main () {
    Test *test = [[Test alloc] init];
    id objResult = [test objProxyMethod];
    NSLog(@"objResult = \"%@\"", objResult);

    return 0;
}
#导入
@协议
@可选的
-(id)objproxy方法;
@结束
@接口返回对象:NSObject
@结束
@接口测试:NSObject
@结束
@接口代理:NSObject
-(id)objproxy方法;
@结束
@实现返回对象
-(无效)解除锁定{
NSLog(@“错误:”);
NSLog(@“我要被解约了!”);
NSLog(@“这不应该发生!”);
}
-(NSString*)说明{
返回@“空白对象!”;
}
@结束
@实现代理
-(id)objProxyMethod{
NSLog(@“在[Proxy-objProxyMethod]!”);
return[[ReturnObject alloc]init];
}
@结束
@实施测试
-(void)转发调用:(NSInvocation*)调用{
NSLog(@“转发调用!”);
Proxy*Proxy=[[Proxy alloc]init];
[调用invokeWithTarget:proxy];
NSUInteger长度=[[invocation methodSignature]methodReturnLength];
如果(长度==8){
id结果;
[调用getReturnValue:&结果];
}
}
@结束
int main(){
Test*Test=[[Test alloc]init];
id objResult=[test objProxyMethod];
NSLog(@“objResult=\“%@\”,objResult);
返回0;
}
如果我注释掉
[invocation getReturnValue:&result],返回的对象未被解除锁定。我不知道这是否是一个bug,或者只是我误解了
NSInvocation
的工作原理

if (length == 8) {
    id result; //this is nil (its also a stack allocated pointer)
    [invocation getReturnValue:&result];  //sets the value to an object
}

...method ends object is deallocated
必须将结果设置为未堆栈分配的指针或未调用getReturnValue

API可能假设,由于调用了getReturnValue,您将保留(并可能使用返回值)。你没有。删除getReturnValue时,返回值在main方法中是否正确返回? 苹果文档说返回值是自动返回的


我假设它是这样。

问题是,
结果在默认情况下是
\uu strong
,因此当它超出范围时,编译器会为它生成一个
版本。但是
getReturnValue:
没有给您返回对象的所有权,所以您的方法不应该释放它

您可以通过更改
result
的声明来解决此问题:

__unsafe_unretained id result;
这可以防止编译器在
结果
超出范围时为
结果
生成
版本
。如果需要保留,可以将其复制到另一个变量

您还可以向
NSInvocation
添加一个类别,以便为您处理此问题:

@interface NSInvocation (ObjectReturnValue)

- (id)objectReturnValue;

@end

@implementation NSInvocation (ObjectReturnValue)

- (id)objectReturnValue {
    __unsafe_unretained id result;
    [self getReturnValue:&result];
    return result;
}

@end

...
    if (length == 8) {
        id result = [invocation objectReturnValue];
    }
...

您也可以将其报告为bug。我希望编译器,或者至少是静态分析器,警告您正在将指向强
id
的指针转换为空指针

这是因为ARC无法管理作为指针写入的对象。只能直接分配

错:

id结果;
[调用getReturnValue:&结果];
对:

void*指针;
[调用getReturnValue:&指针];
id结果=(_桥id)指针//正确,ARC将在赋值后保留指针

我使用的是ARC,默认情况下变量是
\uu strong
,因此
保留
正在发生,只是不可见。id是堆栈分配的变量。它不在堆上,在方法调用结束时不再存在,因为调用堆栈上没有显式返回值,所以ARC可能会在那里插入一个版本,这就是我不使用ARC的原因。很高兴你得到了答案。是的,ARC似乎在作用域的末尾插入了一个
版本
。如果该值设置为堆栈上没有的值,ARC可能会让它生效,但关于使用_魔术的答案很好。谢谢!如果我使用
\uuuu弱
而不是
\uu不安全\uu未恢复
,它仍然有效吗?到目前为止,我在使用
\uuuu-weak
时没有收到任何错误,但我只是想确定一下。您不应该在此处使用
\uu-weak
而不是
\uu-unrestained
。弱变量需要使用
objc\u storeWeak
运行时函数进行设置,而
-[NSInvocation getReturnValue:][/code>显然不这样做。如果声明
\uuu弱id result
,编译器将在
结果
超出范围时生成对
objc\u destro弱
的调用。由于未使用
objc\u storeWeak
设置
result
,因此行为未定义。我明白了。谢谢你的解释,这很有帮助。