这是我用来测试行为的独立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
的工作原理。
答案 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说返回值是自动返回的。
我假设确实如此。