[英]NSInvocation getReturnValue: called inside forwardInvocation: makes the returned object call dealloc:
這是一個獨立的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;
}
如果我注釋掉[invocation getReturnValue:&result];
,返回的對象不是dealloc
ated。 我不知道這是一個錯誤,還是我誤解了NSInvocation
工作原理。
問題是默認情況下result
為__strong
,因此當它超出范圍時,編譯器會為其生成一個release
。 但是getReturnValue:
沒有給你返回對象的所有權,所以你的方法不應該釋放它。
您可以通過更改result
聲明來解決此問題:
__unsafe_unretained id result;
這可以防止編譯器在result
超出范圍時生成result
的release
。 如果需要保留它,可以將其復制到另一個__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
這是因為ARC無法管理作為指針編寫的對象。 只能直接分配。
錯誤:
id result;
[invocation getReturnValue:&result];
對:
void *pointer;
[invocation getReturnValue:&pointer];
id result = (__bridge id)pointer; //Correct, ARC will retain pointer after assignment
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說返回值是自動返回的。
我假設它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.