先來看一段代碼
NSMutableDictionary *attributeQuery = [query mutableCopy];
[attributeQuery setObject: (id) kCFBooleanTrue forKey:(__bridge_transfer id) kSecReturnAttributes];
CFTypeRef attrResult = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) attributeQuery, &attrResult);
這段代碼在Leaks中在第四行會報(bào)內(nèi)存泄漏吨灭,
一開始還以為是第一個(gè)參數(shù)中的__bridge
問題,當(dāng)把__bridge
改成__bridge_retained
之后內(nèi)存泄漏報(bào)的更嚴(yán)重了饿凛。
分析:
首先這里用__bridge
是沒有問題的,此時(shí)attributeQuery
的引用計(jì)數(shù)是1氓仲,而__bridge
關(guān)鍵字并沒有牽涉到內(nèi)存管理權(quán)的轉(zhuǎn)移朗恳,也就是說attributeQuery
的內(nèi)存還是受ARC管理,等第四行代碼運(yùn)行之后attributeQuery
可以正常收到release
消息引用計(jì)數(shù)變?yōu)?內(nèi)存被系統(tǒng)正澄颠叮回收床蜘。那這里的問題到底出在哪呢?
這時(shí)候再仔細(xì)看后面第二個(gè)參數(shù)蔑水,傳遞的是一個(gè)地址邢锯,可以大膽的猜測SecItemCopyMatching內(nèi)部實(shí)現(xiàn)中對的第二個(gè)參數(shù)指向的內(nèi)存做了一次retain操作:
OSStatus SecItemCopyMatching(CFDictionaryRef query, CFTypeRef * __nullable CF_RETURNS_RETAINED result) {
....
if (result) {
result = CFCreate(....); //retain here
}
....
return ....;
}
并且SecItemCopyMatching
函數(shù)中也第二個(gè)參數(shù)前也明確有CF_RETURNS_RETAINED
關(guān)鍵字,先來看看CF_RETURNS_RETAINED
是什么:
#ifndef CF_RETURNS_RETAINED
#if __has_feature(attribute_cf_returns_retained)
#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
#else
#define CF_RETURNS_RETAINED
#endif
#endif
這里有關(guān)于CF_RETURNS_RETAINED
的解釋搀别。
意思是說有CF_RETURNS_RETAINED
標(biāo)記的參數(shù)或者返回值它的調(diào)用發(fā)要負(fù)責(zé)對其作release
操作丹擎。
說道這里結(jié)論已經(jīng)很明顯了,在這段代碼中由于第二個(gè)參數(shù)使用后沒有release
導(dǎo)致內(nèi)存泄漏歇父。
正確的代碼應(yīng)該是這樣:
NSMutableDictionary *attributeQuery = [query mutableCopy];
[attributeQuery setObject: (id) kCFBooleanTrue forKey:(__bridge_transfer id) kSecReturnAttributes];
CFTypeRef attrResult = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) attributeQuery, &attrResult);
//after use attrResult ....
if (attrResult) {
CFRelease(attrResult);
}
在attrResult
使用完之后需要將其release才行蒂培。