內存管理:
1.作用範圍:
任何繼承了NSObject的對象,堆基本數據類型無效如:int a ,float price;;等
2.原理:
每個對象內部都保存了一個與之相關的整數,稱爲引用計數器,
當使用alloc new copy創建一個對象的時候,對象的引用計數器被設置爲1
每給對象發送一次retain消息,可以使引用計數器+1;
給對象發送一條release消息,可以使引用計數器-1;
當一個對象的引用計數器爲0時,那麼它將被銷燬,其佔用的內存被系統回收,OC也會自動向對象發送一條dealloc消息,一般會重寫dealloc方法,在這裏,釋放相關資源,一定不要直接調用dealloc方法:
可以給對象發送retaincount消息,獲得當前的因數計數器數值。
3.retain 和release :
1,如果你想知道一個對象是不是被回收,方法:重寫父類的dealloc方法:
注意:一定要調用super的dealloc方法,而且最後放在最後面調用。([super dealloc ])
2.如果一個對象調用了release 的操作,並且他的引用計數器已經爲0,如果你再次調用他的release方法:這時候就會發生野指針錯誤:
野指針錯誤:你調用了本不屬於你的內存空間,你既然已經釋放了本來你的內存,那麼現在那塊內存已經不屬於你了,你在調用release方法,說明你又聲明那塊內存是屬於你的,這時候就會發生野指針 錯誤。
注意:當一個對象retain爲0的時候,這時候你就不能再調用他的retainCound方法,因爲一個被釋放的對象,沒有內存,不再去進行訪問會發生野指針錯誤。
3.如果你在創建對象的時候,加上autorelease,那麼編譯器會在一個適當的時機釋放對象,這 樣就不需要你自己手動釋放對象的內存了
4.內存管理法則:
1.誰創建,誰釋放(“誰污染,誰治理”),如果你通過alloc ,new ,copy來創建一個對象,那麼你必須調用release或autorelease ,如果不是你創建的,你就不用去釋放。
2.一般除了alloc ,new copy之外的方法創建的對象都被聲明瞭autorelease
3.誰retain ,誰release ,只要你調用了retain ,無論這個對象是如何產生的,你都要調用release;
5.對象之間的內存管理:
前提:如果一個類A作爲另外一個類B的成員變量,並且訪問A的數據成員的是否,如果在main函數中調用了類B的一個方法,這時候會調用A的對象進行初始化A的成員變量,當在該方法中銷燬後,類B又訪問了一個方法2,這時候仍然讓類A的對象進行初始化操作,這時候會出現野指針錯誤,
原因:由於在方法1中已經釋放了A對象,所以A對象所指向的成員變量的內存回收,如果你再進行調用,就會指向一個不屬於自己的內存空間,這是很危險的。
解決辦法,在set方法裏裏面設施對象的retain操作,並進行release,前提,是判斷傳進來的對象是不是本身。如果是本身那就釋放掉原來對象的指向,如果是一個新的,那就沒有必要進行release,因爲,新對象本來計數器爲0.你再release,就會錯誤;
代碼如下:
類B 中的.M文件
- (id)initWithAge:(int)age{
if ( self= [super init]) {
_age = age;
}
return self;
}
#pragma mark 回收對象
- (void)dealloc {
// 釋放Book對象
[_book release];
//[self.book release];
NSLog(@"student:%i被銷燬了", _age);
[super dealloc];
}
#pragma mark - getter和setter
- (void)setBook:(Book*)book {
if (_book!= book) {
// 先釋放舊的成員變量
[_book release];
// 再retain新傳進來的對象
_book = [book retain];
}
}
- (Book *)book {
return _book;
}
#pragma mark - 公共方法
#pragma mark 讀書
- (void)readBook {
NSLog(@"當前讀的書是:%f", _book.price);
}
main函數:
void test(Student*stu) {
// book:1 引用計數器
Book *book = [[Book alloc] initWithPrice:3.5];
// book:2
stu.book = book;
// book:1
[book release];
//book2:1
Book *book2 = [[Book alloc] initWithPrice:4.5];
//book2:2
stu.book = book2;
// book2:2
stu.book = book2;
// book2:1
[book2 release];
// book2:1
stu.book = book2;//如果再次調用,book2的retaiin也不會變
}
void test1(Student*stu) {
[stu readBook];
}
int main(intargc, const char* argv[])
{
@autoreleasepool {
// stu:1
Student *stu = [[Student alloc] initWithAge:10];
// stu:1
//book:1
//book2:1
test(stu);
// stu:1
//book:1
//book2:1
test1(stu);
// stu:0
//book2:0
//book:1
[stu release];
}
return 0;
}