一道關(guān)于__autoreleasing的面試題

前一段在一個公眾號里看到一個面試題,也是WWDC中的一段代碼,如下:

- (BOOL)validateDictionary:(NSDictionary *)dict usingChecker:(Checker *)checker error:(NSError **)error {
   __block BOOL isValid = YES;
  [dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
    if([checker checkObject:obj forKey:key]) return;
    *stop = YES;isValid = NO;
    if(error) *error = [NSError errorWithDomain:...];
  }];
  return isValid;
}

對內(nèi)存管理熟悉的同學(xué)應(yīng)該很快能發(fā)現(xiàn)這段代碼的問題。這段代碼主要涉及兩個點。第一是error參數(shù)的類型,error參數(shù)的類型應(yīng)該為(NSError *__autoreleasing *))。第二點是某些類的方法會隱式地使用自己的autorelease pool,NSDictionary[enumerateKeysAndObjectsUsingBlock]方法就是這樣,

所以這段代碼可以翻譯如下:

 - (BOOL)validateDictionary:(NSDictionary *)dict usingChecker:(Checker *)checker error:(NSError **)error {
    __block BOOL isValid = YES;
    [dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
        @autoreleasepool{
        if([checker checkObject:obj forKey:key]) return;
          *stop = YES;isValid = NO;
          if(error) *error = [NSError errorWithDomain:...];
     }];
    return isValid;
    }
} 

下面我們來說一下為什么這樣寫會有問題。

首先,__autoreleasing這個關(guān)鍵字在ARC中主要用在參數(shù)傳遞返回值(out-parameters)和引用傳遞參數(shù)(pass-by-reference)的情況下。比如常用的NSError的使用:

NSError *__autoreleasing error;
if (![data writeToFile:filename options:NSDataWritingAtomic error:&error])
{
    NSLog(, error);
}

(在上面的writeToFile方法中error參數(shù)的類型為(NSError *__autoreleasing *)

注意,如果你的error定義為了strong型,那么,編譯器會幫你隱式地做如下事情,保證最終傳入函數(shù)的參數(shù)依然是個__autoreleasing類型的引用。

NSError *error;
NSError *__autoreleasing tempError = error;// 編譯器添加
if(![data writeToFile:filename options:NSDataWritingAtomic error:&tempError])
{
    error = tempError;// 編譯器添加
    NSLog(@"Error: %@", error);
}

所以為了提高效率,避免這種情況,我們一般在定義error的時候?qū)⑵渎暶鳛?code>__autoreleasing類型的:

NSError *__autoreleasing error;

在這里,加上__autoreleasing之后,相當(dāng)于在MRC中對返回值error做了如下事情:

*error = [[[NSError alloc] init] autorelease];

\**error指向的對象在創(chuàng)建出來后,被放入到了autoreleasing pool中,等待使用結(jié)束后的自動釋放,函數(shù)外error的使用者并不需要關(guān)心\**error指向?qū)ο蟮尼尫拧?/p>

但是在上面的代碼中被__autoreleasing修飾的error被放到autoreleasepool里,等autoreleasepool釋放的時候error會被釋放掉,這樣在外面再訪問error的話就會報錯了。
如果要解決這個問題可以在便利前新建一個NSError對象,遍歷完再對傳入的error賦值。

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

相關(guān)閱讀更多精彩內(nèi)容

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