半自動管理內存,MRC
內存管理:如何正確釋放堆上的空間
內存壓根兒就沒釋放---------內存洩露
在使用之前,內存被釋放了------提前釋放
釋放過後又釋放內存---------重復釋放
非自動管理內存的使用原則:
alloc retain new以copy開頭的方法以mutableCopy開頭的方法,都要相應的使用release autorelease
自己收拾的自己工作
//retainCount專門用來計數引用計數
//retain,copy,new,mutableCopy給計數器加1 (方法)
//release給計數器減1(方法) 當retainCount=0,內存釋放
int main() { Car *car = [[Car alloc] init]; Person *p1 = [[Person alloc] init]; [p1 setCar:[car retain]]; NSLog(@"%ld",[[p1 car] retainCount]); Person *p2 = [[Person alloc] init]; [p2 setCar:[car retain]]; NSLog(@"%ld",[[p2 car] retainCount]); [[p2 car] release]; NSLog(@"car = %ld",[car retainCount]); [p2 release]; [[p1 car] release]; NSLog(@"car = %ld",[car retainCount]); [p1 release]; [car release]; }
init property
setter dealloc
readwrite,readonly,assign,retain,copy,nonatomic屬性的作用
@property是一個屬性訪問聲明,擴號內支持以下幾個屬性:
1,getter=getterName,setter=setterName,設置setter與getter的方法名
2,readwrite,readonly,設置可供訪問級別
2,assign,setter方法直接賦值,不進行任何retain操作,為了解決原類型與環循引用問題
3,retain,setter方法對參數進行release舊值再retain新值,所有實現都是這個順序(CC上有相關資料)
4,copy,setter方法進行Copy操作,與retain處理流程一樣,先舊值release,再Copy出新的對象,retainCount為1。這是為了減少對上下文的依賴而引入的機制。
copy是在你不希望a和b共享一塊內存時會使用到。a和b各自有自己的內存。
5,nonatomic,非原子性訪問,不加同步,多線程並發訪問會提高性能。注意,如果不加此屬性,則默認是兩個訪問方法都為原子型事務訪問。鎖被加到所屬對象實例級(我是這麼理解的...)。
atomic和nonatomic用來決定編譯器生成的getter和setter是否為原子操作。在多線程環境下,原子操作是必要的,否則有可能引起錯 誤的結果。加了atomic,setter函數會變成下面這樣:
property 與@synthesize
當你定義了一系列的變量時,需要寫很多的getter和setter方法,而且它們的形式都是差不多的,,所以Xcode提供了@property和@synthesize屬性,@property用在 .h 頭文件中用作聲明,@synthesize用在.m 文件中用於實現。 如下,新建一個基於“Command Line Tool”的項目,名為“property”,再新建一個Student類, 傳統的寫法是: Student.h [cpp] view plaincopyprint? // // Student.h // property // // Created by Rio.King on 13-8-25. // Copyright (c) 2013年 Rio.King. All rights reserved. // #import@interface Student : NSObject { int age; int no; } //age的getter和setter方法聲明 - (int)age; - (void)setAge:(int)newAge; //no的getter和setter方法聲明 - (int)no; - (void)setNo:(int)newNo; @end Student.m [cpp] view plaincopyprint? // // Student.m // property // // Created by Rio.King on 13-8-25. // Copyright (c) 2013年 Rio.King. All rights reserved. // #import "Student.h" @implementation Student //age的getter和setter方法的實現 - (int)age { return age; } -(void)setAge:(int)newAge { age = newAge; } //no的getter和setter方法的實現 - (int)no { return no; } - (void)setNo:(int)newNo { no = newNo; } @end main.m [cpp] view plaincopyprint? // // main.m // property // // Created by Rio.King on 13-8-25. // Copyright (c) 2013年 Rio.King. All rights reserved. // #import #import "Student.h" int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... Student *stu = [[Student alloc] init]; stu.age = 100;//這句相當於setter方法 NSLog(@"age is %i", stu.age);//這裡的 stu.age 相當於getter方法 [stu release]; } return 0; } ------------------------------------------------------------------------------------------------------------------------ 用@property和@synthesize的寫法是: Student.h [cpp] view plaincopyprint? // // Student.h // property // // Created by Rio.King on 13-8-25. // Copyright (c) 2013年 Rio.King. All rights reserved. // #import @interface Student : NSObject { int age; int no; } //當編譯器遇到@property時,會自動展開成getter和setter的聲明 @property int age; @property int no; @end Student.m [cpp] view plaincopyprint? // // Student.m // property // // Created by Rio.King on 13-8-25. // Copyright (c) 2013年 Rio.King. All rights reserved. // #import "Student.h" @implementation Student //@synthesize 會自動生成getter和setter的實現 //@synthesize 默認會去訪問age,no,height同名的變量,, //如果找不到同名的變量,會在內部自動生成一個私有同名變量age,no,height,, //因此Student.h 中的這幾個變量也可以省略不寫。 @synthesize age,no; @end main.m [cpp] view plaincopyprint? // // main.m // property // // Created by Rio.King on 13-8-25. // Copyright (c) 2013年 Rio.King. All rights reserved. // #import #import "Student.h" int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... Student *stu = [[Student alloc] init]; stu.age = 100; NSLog(@"age is %i", stu.age); [stu release]; } return 0; } 幾點說明: 1.在Xcode4.5及以後的版本中,可以省略@synthesize ,編譯器會自動幫你加上getter 和 setter 方法的實現,並且默認會去訪問 _age這個成員變量,如果找不到_age這個成員變量,會自動生成一個叫做 _age的私有成員變量。 2.建議變量名用"_"前綴作為開頭,但我看big Nerd 那本書裡是不用的,個人也比較習慣 big Nerd 的那種寫法,所以變量名就不加前綴了。Y^o^Y
自動釋放池是什麼,如何工作
當您向一個對象發送一個autorelease消息時,Cocoa就會將該對象的一個引用放入到最新的自動釋放池。它仍然是個正當的對象,因此自動釋放池定義的作用域內的其它對象可以向它發送消息。當程序執行到作用域結束的位置時,自動釋放池就會被釋放,池中的所有對象也就被釋放。
1. ojc-c是通過一種"referring counting"(引用計數)的方式來管理內存的, 對象在開始分配內存(alloc)的時候引用計數為一,以後每當碰到有copy,retain的時候引用計數都會加一, 每當碰到release和autorelease的時候引用計數就會減一,如果此對象的計數變為了0, 就會被系統銷毀.
2. NSAutoreleasePool 就是用來做引用計數的管理工作的,這個東西一般不用你管的.
3. autorelease和release沒什麼區別,只是引用計數減一的時機不同而已,autorelease會在對象的使用真正結束的時候才做引用計數減一.
ARC
1. ojc-c是通過?一種"referringcounting"(引?用計數)的?方式來管理內存的,對象在開始分配內存(alloc)的時候引?用計數為?一,以後每當碰到有copy,retain的時候引?用計數都會加?一,每當碰到release和autorelease的時 候引?用計數就會減?一, 如果此對象的計數變為了0,就會被系統銷毀 ARC的規則非常簡單:只要還有一個變量指向對象,對象就會保持在內存中。使用ARC後,不需要再手動調用retain, release, autorelease,因為編譯器處理了一切。 ARC property關鍵字
新關鍵字strong,__strong, weak, __weak(“__”為雙下劃線,(unsafe_unretained,__unsafe_unretained為iOS4.0不支持weak而使用,等同於assign,目前可以不考慮)strong 強引用等同於非ARC的retain
@property (nonatomic, retain) 改為使用@property (nonatomic, strong)
成員變量默認也為strong屬性,可寫作__strong NSString *str; 或省略直接寫為NSString *str;
方法中的strong變量,在方法後會自動釋放,類的strong成員變量在類釋放時會自動釋放。
weak 弱引用
與assign類似,但不全相同。當對象釋放時會自動設置為nil而不需顯式的設置。
如:
__weak NSString *testStr;- (void)test
{
NSString *abc = [NSString stringWithFormat:@"abc"];testStr = abc;
abc = [NSString stringWithFormat:@"def"];
// testStr會自動等於nil, 即使沒有立刻變為nil,在下一個程序循環中也會變為nil,這點與assign不同,assign仍然會有指向空地址的指針,需要手動設為nil,否則再使用就造成crash
}
delegate及xib的outlet 的屬性應該設置為@property @property (nonatomic, weak)
copy和之前的copy一樣,復制一個對象並創建strong關聯
注意點只要還有一個變量指向對象,對象就會保持在內存中。處理不好就會造成對象不會釋放。比如:
NSTimerNSTimer *timer;
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:selfselector:@selector(timerAction) userInfo:nil repeats:YES];
timer的repeat會對self有引用,而self也對timer有引用,即使頁面返回了,self及timer也不會釋放。
解決方法是,在頁面返回前停止timer [timer_ invalidate],可視實際情況放在viewWillDisapper裡執行。(放在dealloc沒用,頁面沒有釋放不會執行dealloc)
延時執行
[self performSelector:@selector(delayFunc) withObject:nilafterDelay:5];
即使頁面返回,也必須等此延時方法執行後才會釋放。因此需要在頁面返回前執行
[NSObject cancelPreviousPerformRequestsWithTarget:self];
(當然這裡指的是一般情況,必須要此方法執行的話可以不用寫這句,特殊情況特殊處理:)
不過 ARC 只能作用於 Objective-C 對象,不能釋放 Core Foundation對象。 因此這裡你仍然需要調用 CFRelease()來釋放該對象。
ARC下__strong和__weak的區別
先用Xcode新建一個命令行工程
新建一個Person類
在.m文件中重寫dealloc函數
- (void)dealloc
{
NSLog(@"Person is dealloc");
}
先了解ARC的基本原理
/*
ARC的判斷准則:只要沒有強指針指向對象,就會釋放對象
指針分2種:
1>強指針:默認情況下,所有指針都是強指針__strong
2>弱指針: __weak
*/
打開main函數 第一個測試 int main(int argc, const char * argv[]) { @autoreleasepool { Person *p = [[Person alloc]init]; //有一個強指針指向Perosn對象 //在這裡 把p為空 p = nil; //這行代碼過後 清空指針對象沒有強指針指向 對象會被釋放 /*會打印*/ /* Person is dealloc */ NSLog(@"-------"); } return 0; } 第二個測試 int main(int argc, const char * argv[]) { @autoreleasepool { Person *p = [[Person alloc]init]; //有一個強指針指向Perosn對象 Person *p2 = p; //p2也指向Person對象 就有兩個強指針指向 p = [[Person alloc]init];//創建一個新對象讓p來指向 但另外一個Person對象仍有強指針指向 NSLog(@"-------"); } //所以對象會在程序結束後釋放 return 0; } 下面看弱指針的測試 int main(int argc, const char * argv[]) { //接下來看若指針 // __strong 聲明強指針 // __weak 弱指針 Person *p = [[Person alloc]init]; __weak Person *p2 = p;//聲明一個弱指針 指向對象 p = nil; //把強指針指向變為空 對象沒有強指針指向 會被釋放 /* 只要強指針指向的對象不存在 ARC會自動給指向該對象的弱指針清空 這樣就會防止野指針錯誤 */ p2 = nil; //若指針不能決定對象的釋放 NSLog(@"----------"); return 0; }
關於ARC使用總結
一.OC的ARC就是自動引用計數 [提示]簡單點說就是讓編譯器完成堆空間的引用計數加減,自動釋放.程序員不再寫retain和release方法 [注意]OC的自動內存管理,不同與JAVA的垃圾回收.而是在預處理的時候,直接在應該保留的地方,添加retain,在應該釋放的地方,添加release,其實就是自動添加代碼. 二.ARC的局限性 1.使用ARC,可能因為代碼的不規范,導致內存提前釋放. 2.導入一些第三方庫,或者導入舊代碼,這些代碼不支持ARC. 三.解決ARC的局限性 1.將不使用ARC的代碼轉成ARC代碼 Edit—>Refactor—>Convert to ARC 2.ARC非ARC混編 //同一個工程中,部分文件使用ARC,部分文件不使用ARC Build phase —>Complie Source -fno-objc-arc 四.使用ARC的技巧 1.四個關鍵字 修飾引用 __strong(強引用) 缺省屬性,其修飾的對象指針,指向哪個對象,會對該對象retain,離開哪個對象,會對該對象release. __weak(弱引用) 其修飾的對象指針,指向任何對象都不會retain. 這樣的指針指向的對象隨時可能消失.如果對象消失了,這個指針會自動變成nil. //在IOS編程中,代理對象使用弱引用 __unsafe_unretained 其修飾的對象指針,指向任何對象都不retain. 當指向的對象消失,該指針不會變成nil,仍然指向已經釋放的對象 __auotoreleasing 只用來修飾需要被傳入地址的指針. 如:__autoreleasing NSError *error; &error; 2.屬性的()參數,原則上,不能寫retain copy了,只能寫strong,如果不想寫retain,可以寫weak [注意] 實際上ARC對這方面很寬松,寫了retain也沒關系 3.id指向對象,不能用void *p指向對象 int a; void *p = &a; id p = [[NSObject alloc] init]; 4.C的結構體中,不能聲明對象指針.否則這個指針不會進行內存管理. 5.不能(顯示)手動調用父類的dealloc -(void)dealloc { self.name = nil; //自動調用父類的dealloc }
ARC下的dealloc
眾所周知,iOS開發的時候,使用ARC的話,dealloc函數是不需要實現的,寫了反而會出錯。
但有些特殊的情況,dealloc函數還是需要的。
比如,在畫面關閉的時候,需要把ViewController的某些資源釋放,
在viewDidDissppear不一定合適,viewDidUnload一般情況下只在memory warning的時候才被調用。
不用ARC的情況下,我們自然會想到dealloc函數。
其實ARC環境下,也沒有把dealloc函數禁掉,還是可以使用的。只不過不需要調用[supper dealloc]了。
舉個例子,畫面上有UIWebView,它的delegate是該畫面的ViewController,在WebView載入完成後,需要做某些事情,比如,把indicator停掉之類的。
如果在WebView載入完成之前關閉畫面的話,畫面關閉後,ViewController也釋放了。但由於WebView正在載入頁面,而不會馬上被釋放,等到頁面載入完畢後,回調delegate(ViewController)中的方法,由於此時ViewController已經被釋放,所以會出錯。(message sent to deallocated instance)
解決辦法是在dealloc中把WebView的delegate釋放。