//管理內存有三種方式,
//1.是垃圾回收,java常見的管理內存的方法,系統來檢測對象是否被使用,是否被釋放
//2.MRC手動管理引用計數,iOS管理內存的方式,程序員通過手動的方式來管理對象是否被釋放
//3.ARC自動管理引用計數,基於MRC,系統自動的管理內存,以後我們還是先使用MRC,培養管理內存的習慣
//
// Girl.h
// OC08,09_內存管理
//
// Created by dllo on 15/7/27.
// Copyright (c) 2015年 zhozhicheng. All rights reserved.
//
#import <Foundation/Foundation.h>
//1.聲明協議
@protocol GirlDelegate <NSObject>
@required
-(void)married;
@optional
-(void)cook;
@end
@interface Girl : NSObject
//2.聲明代理人屬性
@property(nonatomic,assign)id<GirlDelegate>delegate;
-(void)getMarry;
@end
//
// Girl.m
// OC08,09_內存管理
//
// Created by dllo on 15/7/27.
// Copyright (c) 2015年 zhozhicheng. All rights reserved.
//
#import "Girl.h"
@implementation Girl
-(void)getMarry{
[self.delegate cook];
}
@end
//
// Boy.h
// OC08,09_內存管理
//
// Created by dllo on 15/7/27.
// Copyright (c) 2015年 zhozhicheng. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Girl.h"
@interface Boy : NSObject<GirlDelegate,NSCopying>
-(void)dealloc;
+(Boy*)boy;
@property(nonatomic,retain)NSString *name;
@property(nonatomic,copy)NSString *hobby;
@property(nonatomic,retain)Girl *girls;
//自定義的初始化方法
-(instancetype)initWithName:(NSString *)name
hobby:(NSString *)hobby;
+(Boy *)boyWithName:(NSString *)name
hobby:(NSString *)hobby;
@end
//
// Boy.m
// OC08,09_內存管理
//
// Created by dllo on 15/7/27.
// Copyright (c) 2015年 zhozhicheng. All rights reserved.
//
#import "Boy.h"
@implementation Boy
-(void)cook{
NSLog(@"做飯吃");
}
-(void)dealloc{
NSLog(@"對象被釋放了");
//把成員變量所有+1操作全部減去
[_name release];
[_girls release];
[_hobby release];
[super dealloc];
}
+(Boy*)boy{
Boy *b=[[Boy alloc] init];
return [b autorelease];
}
//id是void *
//id是泛型指針,可以用在任何方法中,但是instancetype代表實例類型,用在自定義初始化方法,便利構造器作爲返回值類型使用,標識方法會返回一個對象回去
//-(instancetype)init{
// Boy *b=[[Boy alloc] init];
// return [b autorelease];
//}
- (id)copyWithZone:(NSZone *)zone{
Boy *b=[Boy allocWithZone:zone];
b.hobby=_hobby;
b.name=_name;
return b;
}
-(instancetype)initWithName:(NSString *)name
hobby:(NSString *)hobby{
[super self];
if (self) {
self.name=name; //從直接賦值變成方法賦值
_hobby=hobby;
}return self;
}
+(Boy *)boyWithName:(NSString *)name
hobby:(NSString *)hobby{
Boy *b=[[Boy alloc] initWithName:name hobby:hobby];
//寫便利構造器最後別忘了autorelease
return [b autorelease];
}
-(void)setName:(NSString *)name{
if(_name!=name);
[_name release];
_name=[name retain];
}
@end
對象被創建出來之後他的引用計數retainCount就變成1
Boy *boy=[[Boy alloc] init];
NSLog(@"%ld",boy.retainCount);
結果
2015-07-27 17:47:40.331 OC08,09_內存管理[1562:152231] 1
//對對象的引用計數進行+1的操作
// //retain:對對象的引用計數進行+1
Boy *boy=[[Boy alloc] init];
NSLog(@"%ld",boy.retainCount);
[boy retain];
NSLog(@"%ld",boy.retainCount);
[boy retain];
[boy retain];
NSLog(@"%ld",boy.retainCount);
結果
2015-07-27 17:50:13.304 OC08,09_內存管理[1571:153537] 1
2015-07-27 17:50:13.305 OC08,09_內存管理[1571:153537] 2
2015-07-27 17:50:13.305 OC08,09_內存管理[1571:153537] 4
//release:對對象的引用計數進行-1的操作
[boy release];
NSLog(@"%ld",boy.retainCount);
[boy release];
[boy release];
[boy release];
NSLog(@"%ld",boy.retainCount);
結果
2015-07-27 17:54:44.714 OC08,09_內存管理[1580:155505] 1
2015-07-27 17:54:44.715 OC08,09_內存管理[1580:155505] 對象被釋放了
2015-07-27 17:54:44.715 OC08,09_內存管理[1580:155505] 1
註釋
// //如果多次對對象進行釋放,會造成過度釋放,過度釋放也是最常見的內存問題(+1次數小於-1次數)
// //[boy release];
// //當對象的引用計數1->0時,會自動調用dealloc方法,dealloc纔是對應對象釋放的方法
//當對象調用release的時候,他的引用計數是1,這個對象就不再對他的引用計數進行-1操作,而是直接調用dealloc方法,所以我們在訪問對象引用計數還是1
幾個不同類型retain值
NSArray *arr=@[@"1",@"2",@"3",@"4"];
NSLog(@"%ld",arr.retainCount);
NSString *str=@"1111";
NSLog(@"%ld",str.retainCount);
NSMutableString *str2=[NSMutableString stringWithString:@"111111"];
NSLog(@"%ld",str2.retainCount);
NSDictionary *dic=@{@"1":@"2",@"3":@"4"};
NSLog(@"%ld",dic.retainCount);
NSLog(@"%p",str);
NSLog(@"%p",str2);
結果
2015-07-27 17:56:31.134 OC08,09_內存管理[1587:156279] 1
2015-07-27 17:56:31.134 OC08,09_內存管理[1587:156279] -1
2015-07-27 17:56:31.135 OC08,09_內存管理[1587:156279] 1
2015-07-27 17:56:31.135 OC08,09_內存管理[1587:156279] 1
2015-07-27 17:56:31.135 OC08,09_內存管理[1587:156279] 0x100002130
2015-07-27 17:56:31.135 OC08,09_內存管理[1587:156279] 0x100112ac0
註釋
NSString 的對象在全局靜態區,他的引用計數是-1,代表正整數的最大值,其他的對象都在堆區,
Boy *boy=[[Boy alloc] init];
[boy retain];
[boy retain];
NSLog(@"%ld",boy.retainCount);
//release馬上會把對象的引用計數-1,但是autorelease會延遲對對象的計數-1
[boy release];
NSLog(@"%ld",boy.retainCount);
[boy autorelease];
NSLog(@"%ld",boy.retainCount);
//自動釋放池
//只要對象用autorelease釋放會把對象放入到系統的自動釋放池中,等出了池子範圍,對象引用計數自動-1,這個相當於java的垃圾回收,對象釋放由系統來管理
@autoreleasepool {
[boy autorelease];
NSLog(@"%ld",boy.retainCount);
}NSLog(@"%ld",boy.retainCount);
結果
2015-07-27 19:00:44.667 OC08,09_內存管理[1602:162429] 3
2015-07-27 19:00:44.668 OC08,09_內存管理[1602:162429] 2
2015-07-27 19:00:44.668 OC08,09_內存管理[1602:162429] 2
2015-07-27 19:00:44.668 OC08,09_內存管理[1602:162429] 2
2015-07-27 19:00:44.668 OC08,09_內存管理[1602:162429] 1
// 內存管理原則:加多少減多少,加減做到平衡,減多了過度釋放,減少了沒有得到釋放
//對象的所有權:擁有所有權的對象可以對他進行release
Boy *b=[Boy boy];
[b retain];
NSLog(@"%ld",b.retainCount);
[b release];
結果
2015-07-27 19:05:11.838 OC08,09_內存管理[1610:164027] 2
//便利構造器在返回對象的時候會加上一個autorelease,所以用便利構造器創建對象不需要對內存進行管理
NSArray *arr1=[[NSArray alloc] initWithObjects:@"1",@"2", nil];
NSArray *arr2=[NSArray arrayWithObjects:@"1",@"2",nil];
[arr1 release];
NSArray *arr=@[@"1",@"2",@"3",@"4"];
NSArray *newArr=[NSArray arrayWithArray:arr];
NSLog(@"%@",newArr);
NSLog(@"%ld",arr.retainCount);
NSLog(@"%ld",newArr.retainCount);
結果
2015-07-27 19:07:04.008 OC08,09_內存管理[1624:164855] (
1,
2,
3,
4
)
2015-07-27 19:07:04.009 OC08,09_內存管理[1624:164855] 1
2015-07-27 19:07:04.010 OC08,09_內存管理[1624:164855] 1
//把一個不可變的變成可變的
NSArray *arr=@[@"1",@"2",@"3",@"4"];
NSMutableArray *arr1=[NSMutableArray arrayWithArray:arr];
NSMutableArray *arr2=[arr mutableCopy];
[arr2 addObject:@"5"];
NSLog(@"%@",arr2);
NSDictionary *dic=@{@"1":@"2",@"3":@"4"};
NSMutableDictionary *dic1=[dic mutableCopy];
NSLog(@"%@",dic1);
結果
2015-07-27 19:08:34.111 OC08,09_內存管理[1633:165509] (
1,
2,
3,
4,
5
)
2015-07-27 19:08:34.112 OC08,09_內存管理[1633:165509] {
1 = 2;
3 = 4;
}
註釋
//系統的類要是實現copy功能,必須先簽訂拷貝NSCopying協議,然後實現對應的方法
//不可變的數組字典可以通過mutableCopy轉換成可變的數組字典
//mutableCopy出來的對象可變,copy是不可變的
舉例
Girl Boy文件
//
// Girl.h
// OC08,09_內存管理
//
// Created by dllo on 15/7/27.
// Copyright (c) 2015年 zhozhicheng. All rights reserved.
//
#import <Foundation/Foundation.h>
//1.聲明協議
@protocol GirlDelegate <NSObject>
@required
-(void)married;
@optional
-(void)cook;
@end
@interface Girl : NSObject
//2.聲明代理人屬性
@property(nonatomic,assign)id<GirlDelegate>delegate;
-(void)getMarry;
@end
//
// Girl.m
// OC08,09_內存管理
//
// Created by dllo on 15/7/27.
// Copyright (c) 2015年 zhozhicheng. All rights reserved.
//
#import "Girl.h"
@implementation Girl
-(void)getMarry{
[self.delegate cook];
}
@end
//
// Boy.h
// OC08,09_內存管理
//
// Created by dllo on 15/7/27.
// Copyright (c) 2015年 zhozhicheng. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Girl.h"
@interface Boy : NSObject<GirlDelegate,NSCopying>
-(void)dealloc;
+(Boy*)boy;
@property(nonatomic,retain)NSString *name;
@property(nonatomic,copy)NSString *hobby;
@property(nonatomic,retain)Girl *girls;
//自定義的初始化方法
-(instancetype)initWithName:(NSString *)name
hobby:(NSString *)hobby;
+(Boy *)boyWithName:(NSString *)name
hobby:(NSString *)hobby;
@end
//
// Boy.m
// OC08,09_內存管理
//
// Created by dllo on 15/7/27.
// Copyright (c) 2015年 zhozhicheng. All rights reserved.
//
#import "Boy.h"
@implementation Boy
-(void)cook{
NSLog(@"做飯吃");
}
-(void)dealloc{
NSLog(@"對象被釋放了");
//把成員變量所有+1操作全部減去
[_name release];
[_girls release];
[_hobby release];
[super dealloc];
}
+(Boy*)boy{
Boy *b=[[Boy alloc] init];
return [b autorelease];
}
//id是void *
//id是泛型指針,可以用在任何方法中,但是instancetype代表實例類型,用在自定義初始化方法,便利構造器作爲返回值類型使用,標識方法會返回一個對象回去
//-(instancetype)init{
// Boy *b=[[Boy alloc] init];
// return [b autorelease];
//}
- (id)copyWithZone:(NSZone *)zone{
Boy *b=[Boy allocWithZone:zone];
b.hobby=_hobby;
b.name=_name;
return b;
}
-(instancetype)initWithName:(NSString *)name
hobby:(NSString *)hobby{
[super self];
if (self) {
self.name=name; //從直接賦值變成方法賦值
_hobby=hobby;
}return self;
}
+(Boy *)boyWithName:(NSString *)name
hobby:(NSString *)hobby{
Boy *b=[[Boy alloc] initWithName:name hobby:hobby];
//寫便利構造器最後別忘了autorelease
return [b autorelease];
}
-(void)setName:(NSString *)name{
if(_name!=name);
[_name release];
_name=[name retain];
}
@end
運行
//Boy類使用Copy的方法
Boy *boy=[Boy boyWithName:@"張陽陽" hobby:@"玩"];
Boy *newBoy=[boy copy];
NSLog(@"%@",newBoy.name);
//如果自己的類想要實現copy功能,就必須先簽訂NSCopying協議,然後實現對應的協議方法,initWithZone,之後就可以使用copy的功能
NSLog(@"%ld",boy.retainCount);
NSLog(@"%ld",newBoy.retainCount);
結果
2015-07-27 19:13:02.102 OC08,09_內存管理[1644:168242] 張陽陽
2015-07-27 19:14:15.390 OC08,09_內存管理[1653:168927] 1
2015-07-27 19:14:15.390 OC08,09_內存管理[1653:168927] 1
Boy *boy1=[[Boy alloc] init];
[boy1 retain];
[boy1 retain];
NSLog(@"%ld",boy1.retainCount);
NSMutableArray *arr=[NSMutableArray arrayWithObjects:boy1, nil];
NSLog(@"%ld",[arr[0] retainCount]);
結果
2015-07-27 19:14:52.821 OC08,09_內存管理[1660:169279] 3
2015-07-27 19:14:52.822 OC08,09_內存管理[1660:169279] 4
註釋
// 當對象放入到容器Array或者字典中,對面會被容器進行一次持有,就是retain一次,他的引用計數會+1,主要是爲了防止空指針的問題
// //等對象從容器移除掉之後,相應的會-1
Boy *b=[[Boy alloc] init];
Girl *girl=[[Girl alloc]init];
b.girls=girl;
NSLog(@"%ld",girl.retainCount);
Girl *girl2=[[Girl alloc] init];
b.girls=girl2;
NSLog(@"%ld",girl.retainCount);
結果
2015-07-27 19:16:00.235 OC08,09_內存管理[1667:169909] 2
2015-07-27 19:16:00.236 OC08,09_內存管理[1667:169909] 1
一個完整的類寫法
//
// Person.h
// OC08,09_內存管理
//
// Created by dllo on 15/7/27.
// Copyright (c) 2015年 zhozhicheng. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property(nonatomic,retain)NSMutableArray *arr;
@property(nonatomic,copy)NSString *name;
@property(nonatomic,assign)NSInteger age;
-(id)initWithName:(NSString *)name
age:(NSInteger)age;
+(Person *)personWithName:(NSString *)name
age:(NSInteger)age;
@end
//
// Person.m
// OC08,09_內存管理
//
// Created by dllo on 15/7/27.
// Copyright (c) 2015年 zhozhicheng. All rights reserved.
//
#import "Person.h"
@implementation Person
-(id)initWithName:(NSString *)name
age:(NSInteger)age{
self=[super init];
if (self) {
self.name=name;
self.age=age;
//對象創建之後,裏面的數組也會創建好,不用在外面進行創建,避免因爲忘了,造成問題
self.arr=[NSMutableArray array];
}return self;
}
+(Person *)personWithName:(NSString *)name
age:(NSInteger)age{
Person *per=[[Person alloc] initWithName:name age:age];
return [per autorelease];
}
-(void)dealloc{
[_arr release];
[_name release];
//age是棧區的,我們操作的是堆區
}
@end
Person *per=[[Person alloc] initWithName:@"張陽陽" age:20];
[per.arr addObject:@"1" ];
NSLog(@"%@",per.arr);
結果
2015-07-27 19:18:09.427 OC08,09_內存管理[1675:171354] (
1
)