NSInvocation getReturnValue: 内部调用 forwardInvocation: 使返回的对象调用 dealloc: [英] NSInvocation getReturnValue: called inside forwardInvocation: makes the returned object call dealloc:

查看:83
本文介绍了NSInvocation getReturnValue: 内部调用 forwardInvocation: 使返回的对象调用 dealloc:的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Here's a standalone test.m file that I'm using to test the behavior.

编译:clang test.m -o test.app -fobjc-arc -ObjC -framework Foundation.确保已安装 Xcode 命令行工具.

To compile: clang test.m -o test.app -fobjc-arc -ObjC -framework Foundation. Make sure the Xcode command-line tools are installed.

#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];,则返回的对象不是 deallocated.我不知道这是一个错误,还是我误解了 NSInvocation 的工作原理.

If I comment out [invocation getReturnValue:&result];, the returned object isn't deallocated. I don't know if this is a bug, or just me misunderstanding how NSInvocation works.

推荐答案

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

The problem is that result is __strong by default, so when it goes out of scope, the compiler generates a release for it. But getReturnValue: didn't give you ownership of the returned object, so your method shouldn't be releasing it.

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

You can fix this by changing the declaration of result:

__unsafe_unretained id result;

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

This prevents the compiler from generating a release for result when result goes out of scope. If you need to retain it, you can copy it to another, __strong variable.

您还可以向 NSInvocation 添加一个类别来为您处理:

You could also add a category to NSInvocation to handle this for you:

@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

You could also report this as a bug. I would expect the compiler, or at least the static analyzer, to warn you that you're converting a pointer to a strong id to a void pointer. http://bugreport.apple.com

这篇关于NSInvocation getReturnValue: 内部调用 forwardInvocation: 使返回的对象调用 dealloc:的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆