NSInvocation getReturnValue: 内部调用 forwardInvocation: 使返回的对象调用 dealloc: [英] NSInvocation getReturnValue: called inside forwardInvocation: makes the returned object call 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];
,则返回的对象不是 dealloc
ated.我不知道这是一个错误,还是我误解了 NSInvocation
的工作原理.
If I comment out [invocation getReturnValue:&result];
, the returned object isn't dealloc
ated. 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屋!