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

rya*_*hee 6 objective-c nsinvocation

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

编译:clang test.m -o test.app -fobjc-arc -ObjC -framework Foundation.确保已安装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;
}
Run Code Online (Sandbox Code Playgroud)

如果我注释掉[invocation getReturnValue:&result];,则返回的对象不会被删除dealloc.我不知道这是不是一个bug,或者只是我误解了它是如何NSInvocation工作的.

rob*_*off 22

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

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

__unsafe_unretained id result;
Run Code Online (Sandbox Code Playgroud)

这可以防止编译器在超出范围时生成releasefor .如果需要保留它,可以将其复制到另一个变量.resultresult__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];
    }
...
Run Code Online (Sandbox Code Playgroud)

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