簡體   English   中英

NSInvocation getReturnValue:在forwardInvocation內調用:使返回的對象調用dealloc:

[英]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超出范圍時生成resultrelease 如果需要保留它,可以將其復制到另一個__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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM