一、引用計數器
1> 棧和堆
棧
① 主要存儲局部變量② 內存自動回收
堆
① 主要存儲需要動態分配內存的變量② 需要手動回收內存,是OC內存管理的對象
2> 簡介
作用
① 表示對象被引用的次數② 通常由alloc、new、copy與release方法引發③ 動態監測引用計數器的值,當值為0時回收對象所占的內存
使用注意
① 引用計數器一個NSUInteger類型的變量,占用4字節內存② 在對象被創建的時候引用計數器的值被初始化為1③ 每個使引用計數器加1的操作,都有一個引用計數器減1的操作與之 對應
3> 基本概念
僵尸對象
① 所占用的內存已經被回收的對象② 僵尸對象不能再被使用
野指針
① 指向僵尸對象的指針② OC中引用野指針會報錯,錯誤信息:EXC_DAB_access
空指針
① 沒有指向任何內存地址的指針② 空指針的值通常為nil、NULL或0③ 通常在創建指針時將其初始化,避免其指向不確定的內存④ 在對象被銷毀后,通常要將指向對象的指針賦值為nil,避免產生野 指針
4> 基本方法
retain
① 使引用計數器加1② alloc、new、copy等方法會自動調用retain方法③ 每個retain方法都必須對應一個release方法④ 返回值為對象本身
release
① 使引用計數器減1② 沒有返回值③ 用空指針調用release方法不會報錯④ 不是經過alloc方法創建的對象,不需要執行release操作
dealloc
① 在對象被銷毀時調用② 通常需要重寫dealloc方法③ 重寫dealloc方法時,必須在最后調用父類的dealloc方法④ @PRoperty不會影響dealloc方法,只會影響色圖特人和getter
二、多對象內存管理
1> 基本使用
2> set方法的內存管理
基本使用
① 當set方法的參數是OC對象時,通常要在set方法內實現內存管理② 當參數與成員變量不一樣時,才對成員變量執行release操作,對 參數執行retain
set方法的代碼規范
① 基本數據類型:直接賦值② OC對象類型 1)先判斷是不是新對象 2)若是,對就對象執行一次release操作,對新對象執行一次retain 操作 3)否則,不執行操作
dealloc方法的代碼規范
① 對self擁有的所有對象執行一次release操作② 一定要調用父類的dealloc方法,且放在最后③ 在ARC環境下重寫dealloc方法不能調用父類的dealloc方法
3> @property對內存的影響
基本使用
① 為成員變量生成setter和getter② 默認生成的setter執行的是直接賦值,不涉及內從管理③ 若setter的參數是OC對象,需要設置@property的參數,使其生成 內存管理代碼
@property的參數
① 內存管理相關參數 1)retain:release舊對象,retain新對象(適用于OC對象類型) 2)assign:直接賦值(默認,適用于非OC對象) 3)copy:release舊對象,copy新對象② 控制成員變量屬性的參數 1)readwrite:同時生成setter和getter的聲明、實現 2)readonly:只會生成getter的聲明、實現③ 多線程管理相關參數 1)nonatomic:生成setter方法時不加線程管理代碼,性能高 (一般用這個) 2)atomic:生成setter方法時加上線程管理代碼,性能低(默認)④ 指定setter和getter名稱的參數 1)通過setter指定生成的set方法的名稱,通過getter指定生成的 get方法的名稱 2)不影響點語法的使用,點語法在使用時先轉換為對應的set或get 方法 3)通常當get方法的返回值為BOOL類型數據時,對get方法使用, set方法幾乎不用
4> 循環包含與循環引用
循環包含
① 但兩個類的聲明文件循環包含時,通常要在一個文件中用@class 聲明另一個類② 使用規范 1)在.h文件中用@class聲明類 2)在.m文件中用#import包含類的聲明文件
循環引用
① 當兩個OC類循環引用時,會產生內存管理問題② 解決方法 1)在一個類的聲明中,指定@property的內存管理參數為retain 2)在另一個類的生命中,指定@property的內存管理參數為release
三、autorelease
1> 基本使用
作用
① 將調用該方法的對象放進自動釋放池,當池子銷毀時,對池子內所有 的對象執行一次release操作② 通常在對象創建時調用,放回對象本身
自動釋放池的創建方式
① 通過@autoreleasepool{}創建② 通過NSAutoreleasePool類創建
2> 使用注意
3> 常見應用
快速創建一個自動釋放池內的對象
① 通常設計一個類方法,快速創建一個自動釋放池內的對象② 方法名通常以類名開頭③ 創建時要使用self調用alloc、init與autorelease方法,不要使用類名
四、ARC
1> 基本使用
強指針與弱指針
① 強指針 1)通過__strong聲明的指針 2)所有的指針默認都是強指針② 弱指針 1)通過__weak聲明的指針 2)當弱指針指向的對象被釋放,弱指針將被清空
判斷準則
只要沒有強指針指向對象,對象就會被釋放
2> @property的strong和weak參數
3> 循環引用的解決方法
五、示例(多文件)
/* 1.創建一個Person類和一個Dog類,Person類與Dog類是相互用有關系 2.重寫Person類與Dog類的dealloc方法 3.重寫Person類的set方法,實現內存管理代碼 4.自定義Person類構造方法,用于快速創建一個自動釋放池內的Person對象 */ /*****main.m文件******/#import <Foundation/Foundation.h>//包含Person類的聲明文件#import "Person.h"//包含Dog類的聲明文件#import "Dog.h"int main(){ //創建自動釋放池 @autoreleasepool { //創建Dog對象,并加入到自動釋放池中 Dog *d = [[[Dog alloc] init] autorelease]; /*通過調用類方法快速創建一個Person類型的自動釋放池對象 并用Dog初始化新創建的對象的成員變量*/ Person *p = [Person personWithDog:d]; //將指針清空 p = nil; } return 0;}/*****Person.h文件******/#import <Foundation/Foundation.h>//聲明Dog是一個類,Dog.h文件用#import指令@class Dog;@interface Person : NSObject/*通過@property生成dog屬性的getter和setter 并使用參數retain,Dog.h使用assign參數*/@property (nonatomic, retain) Dog *dog;/*自定義方法,快速創建一個Person類型的自動釋放池對象,并用Dog初始化新創建的對象的成員變量*/+ (Person *)personWithDog:(Dog *)dog;@end/*****Person.m文件******/#import "Person.h"//使用@class聲明的類,在實現文件中要用#import指令包含該類的頭文件#import "Dog.h"@implementation Person+ (id)personWithDog:(Dog *)dog{ Person *p = [[[Person alloc] init] autorelease]; //將dog賦值給新創建對象的成員變量 p.dog = dog; return p;}//重寫dealloc方法- (void)dealloc{ NSLog(@"Person對象被釋放"); //釋放person所擁有的屬性 [_dog release]; //調用父類的dealloc方法 [super dealloc];}@end/*****Dog.h文件******/#import <Foundation/Foundation.h>//包含Person.h頭文件,Person.h文件用@class指令#import "Person.h"@interface Dog : NSObject/*通過@property生成person屬性的getter和setter 并使用參數retain,Person.h使用retain參數*/@property (nonatomic, assign) Person *person;@end/*****Dog.m文件******/#import "Dog.h"@implementation Dog//重寫dealloc方法- (void)dealloc{ NSLog(@"Dog對象被釋放"); //釋放Dog所擁有的屬性 [_person release]; //調用父類的dealloc方法 [super dealloc];}@end
新聞熱點
疑難解答