IOS筆記-內存管理

引言:內存管理是OC中很是重要的一起,在實際操做中有許多的細節須要咱們去注意。李傑明老師的視頻由淺到深的詳細講解了內存這個版塊,而且着重強調了內存管理的重要性。在這裏我也詳細總結了關於內存管理的一些知識。ios

管理範圍:任何繼承自NSObject的對象,對基本數據類型無效多線程

一:計數器的基本操做函數

1>計數器的基本結構:引用計數器4字節性能

2>引用計數器的做用atom

當使用alloc(分配存儲空間)、new或者copy建立了一個新對象時,新對象的引用計數器默認值就是1。spa

當計數器爲0時,整個程序退出。.net

當計數器部位0時,佔用的內存不能被回收。線程

3>引用計數器的操做設計

1.retainCount指針

 

 1
 2
 3
 4
// 設計一個Person類
Person *p = [[Person alloc]init];
int a = [p retainCount]; // NSUInteger a = [p retainCount];
NSLog(@"計數器:%d",a); // a = 1(默認)
 來自CODE的代碼片
retainCount.m

 

retainCount:獲取當前計數值

回收:

(1).運行中回收 (好比植物大戰殭屍中的子彈,發出去就要回收)

(2).程序退出  (mian函數沒有結束,程序不會退出)

2.重寫dealloc方法(相似遺言)

當一個對象被回收的時候,就會自動調用這個方法

 

 1
 2
 3
 4
 5
 6
 7
 8
@implementation Person
- (void)dealloc
{
NSLog(@"Person對象被回收")
// super的dealloc必定要調用,並且放在最後面
[super dealloc];
}
@end
 來自CODE的代碼片
dealloc.m

 

3.retain、release

 

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
int main()
{
Person *p = [[Person alloc]init];
[p retain];
// 有retain 就要release
[p release];
// 有alloc 就要release
[p release]; // 運行中回收,調用dealloc
p = nil; // 對象回收,指針也能夠回收。
return 0
}
 來自CODE的代碼片
retain.m

 

retain:返回對象自己,計數器+1;

release:沒有返回值,計數器-1;

注:使用alloc,retain必須使用release

4>殭屍對象
當對象被回收,就是不可用內存,對象叫作殭屍對象,當咱們再去訪問這一塊殭屍對象,就會報錯。當對象被回收,指針爲野指針。這一錯誤就稱爲:野指針錯誤。
OC不存在空指針錯誤,給空指針發送消息不報錯。
[p release]; //報錯
[nil release]; //不報錯
二:set方法的內存管理
1>多對象內存管理
1.只要對象還在使用,這個對象就不會回收
只要你使用對象,對象的計數器就+1
再也不使用對象,對象的計數器就減1
2.誰建立,誰release
若是經過alloc、new、或copy建立,就須要調用release或autorelease。

若是沒有建立,就不用(auto)release。

3.誰retain,誰release

總結:善始善終,有加有減

2>set方法內存管理

例:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
// Book類
@interface Book:NSObject
@end
@implementation Book
- (void)dealloc
{
NSLog(@"Book被回收了")
[super dealloc];
}
@end
 
// Person類
@interface Person:NSObject
{
// Book對象
Book *_book;
}
// book的set方法和get方法
- (void)setBook:(Book *)book;
- (Book *)book;
@end
 
@implementation Person
// book的set方法和get方法
- (void)setBook:(Book *)book
{
_book = [book retain];
}
- (Book *)book
{
return _book;
}
 
- (void)dealloc
{
[_book release]; // 有retain就要release
NSLog(@"Person被回收了")
[super dealloc];
}
@end
int main()
{
Book *b = [[Book alloc] init]; // b = 1
Person *b = [[Person alloc] init]; // p = 1
// p1想佔用b這本書
[p1 setBook:b]; // b = 2;
[b release]; // b = 1;
b = nil;
[p1 release]; // p1 = 0, b =0
p1 = nil;
return 0;
}
 來自CODE的代碼片
多對象內存管理.m
1.對set方法的完善:
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
@implementation Person
- (void)setCar:(Car *)car
{
if(car != car) // 防止重複定義報錯
{
// 對當前正在使用的車(舊車)作一次release
[_car release];
// 對新車作一次retain操做
_car = [car retain];
}
}
@end
 來自CODE的代碼片
set方法完善.m
2.內存管理代碼規範
1.只要調用alloc,必須有release(autorelease)
2.set方法的代碼規範:
(1)基本數據類型:直接複製
 1
 2
 3
 4
- (void)setAge:(int)age
{
_age = age;
}
 來自CODE的代碼片
基本數據類型.m
(2)OC對象類型
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
@implementation Person
- (void)setCar:(Car *)car
{
if(car != car) // 防止重複定義報錯
{
// 對當前正在使用的車(舊車)作一次release
[_car release];
// 對新車作一次retain操做
_car = [car retain];
}
}
@end
 來自CODE的代碼片
set方法完善.m
三:@property的內存管理
在@property語法後面加入小括號,能夠加入一些參數。例如:@property (retain) Book *book;   //retain生成的set方法裏面的做用:release舊值,retain新值。
具體的@property參數有4類
1>內存管理相關參數
retain:release舊值,retain新值
assign:直接賦值(默認爲assign,適用於非OC對象類型)
copy:release舊值,copy新值
2>是否要生成set方法
readwrite:同時生成set、get的聲明、實現(默認狀況)
readonly:只讀。(只生成getting)
3>多線程管理
nonatomic:性能高(目前寫代碼必寫)
atomic:性能低(默認狀況)
4>setter 和 getter方法的名稱
(getter method)  通常用在BOOL類型
(setter method)  這裏的method要有冒號
 1
 2
 3
 4
 5
 6
 7
 8
 9
@property (getter = isRich) BOOL rich;
// 當遇到BOOL類型,返回BOOL類型的方法名通常以is開頭
// OC對象
// @property (nonatomic,retain) 類名 *屬性名
@property (nonatomic,retain) Car *car;
@property (nonatomic,retain) id car; //id類型除外
// 非OC對象類型(int\float\enum\struct)
// @property (nonatomic,assign) 類名 *屬性名
@property (nonatomic,assign) int age;
 來自CODE的代碼片
BOOLis.m
注:同一類參數不可同時寫(除第四類外)。
四:循環retain 和 @class
1>@class的做用:僅僅告訴編譯器,某一個名稱是一個類
@class Person  // 僅僅告訴編譯器,Person是一個類
2>開發中引用一個類的規範
(1)在.h文件中用@class來聲明類
(2)在.m文件中用#import來包含類的全部東西
3>兩端循環引用解決方案
(1)一端用retain
(2)一端用assign
4>兩種方式的區別:
#import方式會包含被引用類的全部信息,包括被引用類的變量和方法;@class方式只是告訴編譯器在A.h文件中B *b 只是類的聲明,具體這個類裏有什麼信息,這裏不須要知道,等實現文件中真正要用到時,纔會真正去查看B類中信息.
例:
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
#import <Foundation/Foundation.h>
 
@class Book;
@interface Student
@property (retain) Book *book;
@end
 
#import "Student.h"
#import "Book.h"
@implementation Student
- (void)dealloc {
[_book release];
[super dealloc];
}
@end
 來自CODE的代碼片
@class.m
注意問題:爲何用@class更好
第一:解決循環retain問題
第二:提升性能
五:autorelease
1>autorelease的基本用法
(1)會將對象放到一個自動釋放池中
(2)當自動釋放池被銷燬時,會對池子裏面的全部對象作一次release操做。
(3)會返回對象自己
(4)調用完autorelease方法後,對象的計數器不變。
2>autorelease的好處
(1)不用再關心對象釋放時間
(2)不用再關心何時調用release
3>autorelease的使用注意
(1)佔用內存較大的對象不要隨便使用autorelease
(2)佔用內存較小的對象使用release沒有太大影響
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
@autoreleasepool
{ // {開始表明建立了釋放池
Person *p = [[[Person alloc] init] autorelease];
p.age = 10;
@autoreleasepool
{
Person *p2 = [[[Person alloc] init] autorelease];
p2.age = 12;
}
} // }結束表明釋放池銷燬
 來自CODE的代碼片
autorelease.m
4>自動釋放池
(1)在ios程序運行過程當中,會建立無數個池子,這些池子都是以棧的結構存在(先進後出)
(2)當一個對象調用autorelease方法時,會將這個對象放在棧頂的釋放池。
5>自動釋放池的建立方式
(1)iOS 5.0之前
 1
 2
NSAutoreleasepool *pool = [[NSAutoreleasepool alloc] init];
[pool release]; // [pool drain]
 來自CODE的代碼片
autoreleasepool.m
(2)5.0以後
@autoreleasepool{
}
實例操做:
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
@interface Person:NSObject
+ (id)person;
+ (id)personWithAge;
@end
 
@implementation Person
+ (id)person
{
return [[self alloc] autorelease];
}
+ (id)personWithAge
{
Person *p = [self person];
p.age = age;
return p;
}
- (void)dealloc
{
NSLog(@"Person被回收了");
[super dealloc];
}
@end
 
#import <Foundation/Foundation.h>
int main()
{
@autoreleasepool
{
// 調用簡單
Person *p = [Person person];
p2.age = 100;
}
 
return 0;
}
 來自CODE的代碼片
實例操做.m
總結:1系統自帶的方法裏面沒有包含alloc、new、copy,說明返回的對象都是autorelease的。
[NSString stringWithFormat:……];
2.開發中常常會提供一些類方法,快速建立一個已經autorelease過的對象。(注:建立對象時不要直接用類名,通常用self)
相關文章
相關標籤/搜索