IOS性能調(diào)優(yōu)系列:Analyze靜態(tài)分析
XCode已經(jīng)提供了非常強(qiáng)大的性能調(diào)優(yōu)工具坝冕,結(jié)合幾個(gè)第三方工具和一些技巧,進(jìn)行性能優(yōu)化非常簡單。
第一篇先寫寫最簡單的孩擂,Analyze靜態(tài)分析。
相信IOS開發(fā)者在App進(jìn)行Build或Archive時(shí)箱熬,會(huì)產(chǎn)生很多編譯警告类垦,這些警告是編譯時(shí)產(chǎn)生的,靜態(tài)分析的過程也類似城须,在XCode Product菜單下蚤认,點(diǎn)擊Analyze對App進(jìn)行靜態(tài)分析。
Analyze主要分析以下四種問題:
1糕伐、邏輯錯(cuò)誤:訪問空指針或未初始化的變量等砰琢;
2、內(nèi)存管理錯(cuò)誤:如內(nèi)存泄漏等;
3氯析、聲明錯(cuò)誤:從未使用過的變量亏较;
4、Api調(diào)用錯(cuò)誤:未包含使用的庫和框架掩缓。
Analyze內(nèi)存泄漏分析:
聲明錯(cuò)誤雪情、邏輯錯(cuò)誤、Api調(diào)用錯(cuò)誤基本在編譯時(shí)都會(huì)有警告你辣,Analyze的主要優(yōu)勢在于靜態(tài)分析內(nèi)存泄漏及代碼邏輯錯(cuò)誤巡通。
比如在開啟arc的環(huán)境下,輸入以下一段代碼:
ARC 和 非ARC 下 oc 對象 和 CF 對象的轉(zhuǎn)換
標(biāo)簽:objective-c內(nèi)存泄露CoreFundation
2014-03-11 11:301231人閱讀評論(0)收藏舉報(bào)
分類:
IOS開發(fā)(123)
版權(quán)聲明:本文為博主原創(chuàng)文章舍哄,未經(jīng)博主允許不得轉(zhuǎn)載宴凉。
在OC和FC之間進(jìn)行轉(zhuǎn)化的時(shí)候,主要是對象的歸屬問題表悬。共有兩種方式:
1弥锄、使用宏,可以標(biāo)識歸屬者從OC到CF蟆沫,還是從CF到OC籽暇。
[objc]view plaincopy
NS_INLINE?CFTypeRef?CFBridgingRetain(idX)?{
return(__bridge_retain?CFTypeRef)X;
}
NS_INLINEidCFBridgingRelease(CFTypeRef?X)?{
return(__bridge_transferid)X;
}
2、使用轉(zhuǎn)化符,如:__bridge饭庞,__bridge_transfer戒悠,__bridge_retained
__bridge:不涉及對象所有關(guān)系改變
__bridge_transfer:給予 ARC 所有權(quán)
__bridge_retained:解除 ARC 所有權(quán)
[objc]view plaincopy
idmy_id;
CFStringRef?my_cfref;
NSString???*a?=?(__bridge?NSString*)my_cfref;//?Noop?cast.
CFStringRef?b?=?(__bridge?CFStringRef)my_id;//?Noop?cast.
NSString???*c?=?(__bridge_transfer?NSString*)my_cfref;//?-1?on?the?CFRef
CFStringRef?d?=?(__bridge_retained?CFStringRef)my_id;//?returned?CFRef?is?+1
非ARC模式下:
[objc]view plaincopy
#pragma?mark?–?View?lifecycle
-?(void)viewDidLoad
{
[superviewDidLoad];
NSLog(@"=%@",?[selfescape:@"LIN986LIN"]);
}
-(NSString*)escape:(NSString*)text
{
return(NSString*)CFURLCreateStringByAddingPercentEscapes(NULL,?(__bridge?CFStringRef)text,NULL,CFSTR("!*’();:@&=+$,/?%#[]"),?CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));
}
ARC模式下:
可以看到xcode自動(dòng)把上面函數(shù)轉(zhuǎn)化為:
[objc]view plaincopy
#pragma?mark?–?View?lifecycle
-?(void)viewDidLoad
{
[superviewDidLoad];
NSLog(@"=%@",?[selfescape:@"wangjun"]);
}
-(NSString*)escape:(NSString*)text
{
return(__bridge_transferNSString*)CFURLCreateStringByAddingPercentEscapes(NULL,?(__bridge?CFStringRef)text,NULL,CFSTR("!*’();:@&=+$,/?%#[]"),?CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));
}
在arc中,CF和OC之間的轉(zhuǎn)化橋梁是 __bridge舟山,有兩種方式:
__bridge_transfer ?ARC接管管理內(nèi)存
__bridge_retained ?ARC釋放內(nèi)存管理
oc 到 CF 的轉(zhuǎn)化绸狐,需要把OC的內(nèi)存管理權(quán)釋放掉。
[objc]view plaincopy
NSString*str?=?[[NSStringalloc]initWithFormat:@"Welcome??,?%@!",name];
CFStringRef?strref?=?(__bridge_retained?CFStringRef)str;
//?do?something?with?strref
CFRelease(strref);
最后由CF進(jìn)行內(nèi)存釋放累盗。
上面代碼等同于:
[objc]view plaincopy
CFStringRef?strref?=?CFBridgingRetain(str);
//?do?something?with?strref
CFRelease(strref);
CF轉(zhuǎn)化為OC時(shí)寒矿,并且對象的所有者發(fā)生改變,則使用CFBridgingRelease()或__bridge_transfer 若债。
OC轉(zhuǎn)化為CF時(shí)符相,并且對象的所有者發(fā)生改變,則使用CFBridgingRetain()或__bridge_retained
當(dāng)一個(gè)類型轉(zhuǎn)化到另一種類型時(shí)拆座,但是對象所有者沒有發(fā)生改變主巍,則使用__bridge.
CF對象和OC對象混用可能出現(xiàn)的問題:
ARC模式下,自動(dòng)回收只針對Objective-C對象有效挪凑,對于Core Foundation對象還是需要我們手動(dòng)進(jìn)行釋放的孕索,CFRelease().
分析下面的情況:
在一個(gè)方法里定義了一個(gè)CGColorRef對象:CGColorRef cf
分別通過以下三種方式給cf賦值后,再使用cf時(shí)會(huì)有什么不同呢躏碳?
方式一:
[objc]view plaincopy
UIColor*?color?=?[[UIColoralloc]initWithRed:0.0fgreen:0.0fblue:0.0falpha:1.0f];
cf?=?color.CGColor;
方式二:
[objc]view plaincopy
cf?=?[[UIColoralloc]initWithRed:0.0fgreen:0.0fblue:0.0falpha:1.0f].CGColor;
方式三:
[objc]view plaincopy
cf?=?[UIColorcolorWithRed:0.0fgreen:0.0fblue:0.0falpha:1.0f].CGColor;
方式一和方式三運(yùn)行沒問題搞旭。方式二后再使用cf會(huì)crash,因?yàn)檫@時(shí)cf已經(jīng)是野指針了。
分析如下:
方式一中肄渗,color對象默認(rèn)是strong強(qiáng)引用镇眷,在這個(gè)方法的生命周期內(nèi)都有效,在退出這個(gè)方法時(shí)才會(huì)被自動(dòng)釋放池釋放翎嫡。所以用它的CGColor是沒有問題的欠动。
方式三中類似,colorWithRed:…這是個(gè)類方法惑申,會(huì)返回一個(gè)autorelease對象具伍,對象在自動(dòng)釋放池釋放之前都有效,所以也不會(huì)出問題圈驼。
方式二中人芽,生成的UIColor對象沒有給任何owner,相當(dāng)于一個(gè)weak弱引用绩脆,alloc之后被馬上釋放了萤厅,所以他的CGColor變量也隨之成了野指針。
ARC下OC對象與CF對象橋接:
下面一行代碼:
[objc]view plaincopy
CFStringRef?s1=?(CFStringRef)[[NSStringalloc]initWithFormat:@”Hello,?%d!”,1];
在ARC下面會(huì)報(bào)編譯問題靴迫,并會(huì)給出推薦的解決方案:
[objc]view plaincopy
CFStringRef?s1=?(__bridge?CFStringRef)[[NSStringalloc]initWithFormat:@”Hello,?%d!”,1];
這里NSString生成的是OC的對象惕味,內(nèi)存由ARC負(fù)責(zé)。s1是CF的對象矢劲,內(nèi)存還是需要自己手動(dòng)管理赦拘。兩個(gè)變量轉(zhuǎn)換時(shí)需要添加橋接標(biāo)識慌随。
上面這種情況下不會(huì)crash芬沉,也不會(huì)有內(nèi)存泄露。因?yàn)閍lloc出來的內(nèi)存會(huì)被ARC回收阁猜,這塊內(nèi)存的所有關(guān)系沒變丸逸。
如果后面加上CFRelease(s1);就會(huì)crash,因?yàn)檫@塊內(nèi)存還是歸ARC管的剃袍,這樣會(huì)過度釋放黄刚。
修改一下:
CFStringRef s1 = (__bridge_retained CFStringRef)[[NSString alloc] initWithFormat:@”Hello, %d!”, 1];
這種情況下,對象的所有權(quán)交給CF對象了民效。就需要加上CFRelease(s1);進(jìn)行釋放憔维,否則會(huì)產(chǎn)生泄露。
再看下面代碼:
[objc]view plaincopy
CFUUIDRef?uu?=?CFUUIDCreate(NULL);
CFStringRef?s2=?CFUUIDCreateString(NULL,?uu);
CFRelease(uu);
NSString*?str?=?(__bridge?NSString*)s2;
NSLog(@”STR:%@”,str);
CFRelease(s2);
這里的uu和s2都需要使用CFRelease釋放畏邢,因?yàn)樗麄儾皇荗C對象业扒,并且是create出來的內(nèi)存,并且所有權(quán)沒有被釋放舒萎。
如果改動(dòng)下面一行代碼:
NSString* str = (__bridge_transfer NSString*)s2;
這時(shí)候運(yùn)行程序會(huì)引起crash程储,因?yàn)閟2的所有權(quán)已經(jīng)交給ARC中的str了,ARC會(huì)負(fù)責(zé)釋放這塊內(nèi)存。
這時(shí)候調(diào)用CFRelease(s2);會(huì)造成過度釋放章鲤。所以應(yīng)該把這么行代給去了摊灭。
注:
ARC模式下,自動(dòng)回收只針對Objective-C對象有效败徊,對于使用create,copy,retain等生成的Core Foundation對象還是需要我們手動(dòng)進(jìn)行釋放的帚呼,CFRelease().
由于iOS中CF框架需要自己釋放內(nèi)存,所以ARC的自動(dòng)釋放內(nèi)存就不管用了,需要我們自己釋放,需要使用CFRelease(<#CFTypeRef cf#>)這個(gè)方法來手動(dòng)釋放內(nèi)存.
一:? ARC模式:NSLog(@”Retain count is %ld”, CFGetRetainCount((__bridge CFTypeRef)myObject));
二 : CF框架:NSLog(@”Retain count is %ld”, CFGetRetainCount(myObject));