關(guān)于ARC與NSInvocation的問題

一、問題

給定如下代碼

@implementation TestHelper
- (NSString*)stringObjects
{
    NSMutableString *s = [NSMutableString string];
    return s;
}

- (void)test_invocation
{
    SEL s = @selector(stringObjects);
    NSMethodSignature*signature = [self methodSignatureForSelector:s];
    NSInvocation*invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.target = self;
    invocation.selector = s;
    [invocation invoke];
    
    id obj = nil;
    [invocation getReturnValue:&obj];
    
}
@end

執(zhí)行完test_invocation后會(huì)發(fā)生什么現(xiàn)象呢?

結(jié)果會(huì)crash,crash的原因是over-release;

二、分析

這里涉及了NSInvocation getReturnvalue的一個(gè)問題

Declaration

  • (void)getReturnValue:(void *)retLoc;
    Parameters

buffer
An untyped buffer into which the receiver copies its return value. It should be large enough to accommodate the value. See the discussion below for more information about buffer.

invocation執(zhí)行后的函數(shù)返回值會(huì)進(jìn)行memcpy給buffer;
這里就隱含了這函數(shù)是一個(gè)非ARC的調(diào)用;

如果傳入的是一個(gè)ARC內(nèi)存管理的指針buffer,并且invocation的函數(shù)返回值又是一個(gè)ARC內(nèi)存管理的對(duì)象,那這里可能會(huì)有ARC處理錯(cuò)誤的問題;

對(duì)于函數(shù)stringObjects其返回的對(duì)象是一個(gè)autorelease的對(duì)象,因此該對(duì)象會(huì)被加入當(dāng)前autoreleasepool并且再稍后被釋放;

而對(duì)于test_invocation函數(shù)其聲明了一個(gè)obj對(duì)象,這個(gè)對(duì)象隱含了其實(shí)一個(gè)__strong修飾的對(duì)象,因此ARC會(huì)自動(dòng)給其生成release代碼;但是[NSInvocation getReturnValue:]并不是ARC規(guī)范的函數(shù),因此這里不會(huì)有自動(dòng)ARC的代碼插入,從而導(dǎo)致obj的值指向了一個(gè)對(duì)象,但是指向時(shí)沒有觸發(fā)ARC生成retain的操作;但由于obj是一個(gè)__strong修飾的指針,所以其會(huì)被ARC自動(dòng)加上release操作;

最終就是:stringObjects返回了一個(gè)autorelease的對(duì)象,接著test_invocation又像這個(gè)對(duì)象發(fā)了一次release消息,再接著當(dāng)前代碼結(jié)束后autoreleasepool又嘗試pop并release該對(duì)象,造成同一個(gè)對(duì)象被release了2次,但其引用計(jì)數(shù)最多時(shí)僅為1次;因此第二次就出現(xiàn)內(nèi)存訪問錯(cuò)誤了;

三、結(jié)語

我們還是要注意各個(gè)函數(shù)的傳參說明,不要踩了坑了;
同時(shí)也要牢記ARC的準(zhǔn)則;另外對(duì)于涉及傳參二級(jí)指針或者void*的都要留意引用計(jì)數(shù)的問題.


順帶,如果只允許修改以上的stringObjects方法,請(qǐng)問怎么修改能保證不掛呢?理論上至少有4種方式/或5種。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容