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

时间:2012-08-08 22:20:34

标签: objective-c nsinvocation

这是我用来测试行为的独立test.m文件。

编译:{{1​​}}。确保已安装Xcode命令行工具。

clang test.m -o test.app -fobjc-arc -ObjC -framework Foundation

如果我注释掉#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; } ,则返回的对象不是[invocation getReturnValue:&result];。我不知道这是一个错误,还是我误解了dealloc的工作原理。

3 个答案:

答案 0 :(得分:22)

问题是result默认为__strong,因此当它超出范围时,编译器会为其生成release。但是getReturnValue:没有给你返回对象的所有权,所以你的方法不应该释放它。

您可以通过更改result

的声明来解决此问题
__unsafe_unretained id result;

这可以防止编译器在release超出范围时为result生成result。如果您需要保留它,可以将其复制到另一个__strong变量。

您还可以向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];
    }
...

您也可以将此报告为错误。我希望编译器,或者至少是静态分析器,警告您将指向强id的指针转换为void指针。 http://bugreport.apple.com

答案 1 :(得分:4)

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

错:

id result;
[invocation getReturnValue:&result];

右:

void *pointer;
[invocation getReturnValue:&pointer];

id result = (__bridge id)pointer; //Correct, ARC will retain pointer after assignment

答案 2 :(得分:0)

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方法中正确返回? apple docs说返回值是自动返回的。

我假设确实如此。