您好,登錄后才能下訂單哦!
person類 -----》.h文件
#import <Foundation/Foundation.h> @interface Person : NSObject<NSCopying> //使用copy必須引入NSCopying協議。。。 // 語義設置 //1.NSString接收了copy協議, //2.大多數規范化 @property (nonatomic , copy)NSString *name; @property (nonatomic , assign)NSInteger age; @property (nonatomic , retain)NSString *sex; @property (nonatomic , copy)NSString *hobby; @property (nonatomic , assign)NSInteger num; #pragma mark ---自定義初始化方法 - (instancetype)initWithName:(NSString *)name age:(NSInteger)age hobby:(NSString *)hobby sex:(NSString *)sex num:(NSInteger)num; @end
person類 -----》.m文件
#import "Person.h" @implementation Person @synthesize name = _name; @synthesize age = _age; @synthesize hobby = _hobby; @synthesize sex = _sex; @synthesize num = _num; - (void)setName:(NSString *)name { if (_name != name) { [_name release]; _name = [name copy]; } } - (NSString *)name { return [[_name retain] autorelease]; } - (void)setAge:(NSInteger)age { _age = age; } - (NSInteger)age { return _age; } - (void)setSex:(NSString *)sex { if (_sex != sex) { [_sex release]; _sex = [sex retain]; } } - (NSString *)sex { return [[_sex retain] autorelease]; } - (void)setHobby:(NSString *)hobby { if (_hobby != hobby) { [_hobby release]; _hobby = [hobby copy]; } } - (NSString *)hobby { return [[_hobby retain] autorelease]; } - (void)setNum:(NSInteger)num { _num = num; } - (NSInteger)num { return _num; } - (instancetype)initWithName:(NSString *)name age:(NSInteger)age hobby:(NSString *)hobby sex:(NSString *)sex num:(NSInteger)num { self = [super init]; if (self) { [self setName:name];//1.0過度版 self.name = name; //2.0終極版 // _age = age; [self setAge:age];//1.0 self.age = age; //2.0 self.sex = sex; self.hobby = hobby; self.num = num; } return self; } - (void)dealloc { NSLog(@"內存被回收了"); [super dealloc]; } - (id)copyWithZone:(NSZone *)zone //假拷貝 { //1. // return self; //2.0 // return [self retain]; //淺拷貝 // Person *p = [[Person alloc] initWithName:self.name age:self.age hobby:self.hobby sex:self.sex num:self.num]; // return p; //深拷貝 Person *p = [[Person alloc] initWithName:self.name age:self.age hobby:self.hobby sex:self.sex num:self.num]; p.name = [self.name copy]; // p.age = [self.age copy]; p.hobby = [self.hobby copy]; p.sex = [self.sex copy]; // p.num = [self.num copy]; return p; } @end
main.m文件。。。。。。
#import <Foundation/Foundation.h> #import "Person.h" int main(int argc, const char * argv[]) { @autoreleasepool { //alloc 開辟內存空間,讓被開辟的內存空間的引用計數變為1 Person *p = [[Person alloc] init]; p.name = @"liuyafang"; p.age = 25; p.sex = @"男"; p.hobby = @"女"; p.num = 201010; //retain 引用計數加1,如果內存空間之前引用計數為1,retain之后變為2 [p retain]; Person *meiren = p; // release在1后,從1->0的時候,自動調用dealloc方法,來回收內存。dealloc時繼承自父類的方法,當對象引用計數為0的時候,由對象自動調用 [p release]; NSLog(@"%@,%ld", p.name , [p retainCount]);//alloc開辟內存空間。0->1 Person *pp = [p retain]; //即指向,又擁有。 [p release]; [pp retain]; pp.name = @"pp"; NSLog(@"%ld,%@", [pp retainCount],pp.name); [pp release]; Person *liu = pp ; [liu retain]; liu.name = @"劉亞方"; NSLog(@"%@,%ld",liu.name , [p retainCount]); [liu release]; //autorelease,未來的某一時刻引用計數減1,這里的某一時刻指在出去autoreleasePool后。 //通過autoreleasepool控制autorelease對象的釋放 //向一個對象發送autoresease消息,這個對象何時釋放,取決于autoreleasepool Person *liuyafang = [[Person alloc] init]; [liuyafang retain]; [liuyafang retain]; [liuyafang retain]; // [liuyafang release]; NSLog(@"liuyafang:%ld", [liuyafang retainCount]); [liuyafang autorelease]; NSLog(@"liuyafang-->%ld", [liuyafang retainCount]); //autorelease只有出去autoreleasepool 之后才能-1才能使用 Person *zhenzi = [[Person alloc] initWithName:@"疹子" age:25 hobby:@"吃人" sex:@"男" num:36]; Person *L = [zhenzi copy]; } //這個是老方法NSAutoreleasePool Person *liuyafang = [[Person alloc] init]; [liuyafang retain]; [liuyafang retain]; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; //autorelease老用法 。。。 [liuyafang autorelease]; [pool release]; NSLog(@"%ld", [liuyafang retainCount]); return 0; }
一、基本原理
(一)為什么要進行內存管理。
由于移動設備的內存極其有限,所以每個APP所占的內存也是有限制的,當app所占用的內存較多時,系統就會發出內存警告,這時需要回收一些不需要再繼續使用的內存空間,比如回收一些不再使用的對象和變量等。
管理范圍:任何繼承NSObject的對象,對其他的基本數據類型無效。
本質原因是因為對象和其他數據類型在系統中的存儲空間不一樣,其它局部變量主要存放于棧中,而對象存儲于堆中,當代碼塊結束時這個代碼塊中涉及的所有局部變量會被回收,指向對象的指針也被回收,此時對象已經沒有指針指向,但依然存在于內存中,造成內存泄露。
(二)對象的基本結構
每個OC對象都有自己的引用計數器,是一個整數表示對象被引用的次數,即現在有多少東西在使用這個對象。對象剛被創建時,默認計數器值為1,當計數器的值變為0時,則對象銷毀。
在每個OC對象內部,都專門有4個字節的存儲空間來存儲引用計數器。
(三)引用計數器的作用
判斷對象要不要回收的唯一依據就是計數器是否為0,若不為0則存在。
(四)操作
給對象發送消息,進行相應的計數器操作。
Retain消息:使計數器+1,改方法返回對象本身
Release消息:使計數器-1(并不代表釋放對象)
retainCount消息:獲得對象當前的引用計數器值
(五) 對象的銷毀
當一個對象的引用計數器為0時,那么它將被銷毀,其占用的內存被系統回收。
當對象被銷毀時,系統會自動向對象發送一條dealloc消息,一般會重寫dealloc方法,在這里釋放相關的資源,dealloc就像是對象的“臨終遺言”。一旦重寫了dealloc方法就必須調用[super dealloc],并且放在代碼塊的最后調用(不能直接調用dealloc方法)
一旦對象被回收了,那么他所占據的存儲空間就不再可用,堅持使用會導致程序崩潰(野指針錯誤)。
二、相關概念和使用注意
野指針錯誤:訪問了一塊壞的內存(已經被回收的,不可用的內存)。
僵尸對象:所占內存已經被回收的對象,僵尸對象不能再被使用。(打開僵尸對象檢測)
空指針:沒有指向任何東西的指針(存儲的東西是0,null,nil),給空指針發送消息不會報錯
注意:不能使用[p retaion]讓僵尸對象起死復生。
三、內存管理原則
(一)原則
只要還有人在使用某個對象,那么這個對象就不會被回收;
只要你想使用這個對象,那么就應該讓這個對象的引用計數器+1;
當你不想使用這個對象時,應該讓對象的引用計數器-1;
(二)誰創建,誰release
(1)如果你通過alloc,new,copy來創建了一個對象,那么你就必須調用release或者autorelease方法
(2)不是你創建的就不用你去負責
(三)誰retain,誰release
只要你調用了retain,無論這個對象時如何生成的,你都要調用release
(四)總結
有始有終,有加就應該有減。曾經讓某個對象計數器加1,就應該讓其在最后-1.
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。