您的位置:首页 > 职场人生

黑马程序员-OC内存管理

2014-12-25 10:02 435 查看
[align=center]------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------[/align]
内存管理

1.移动设备的内存极其有限,每个app所能占用的内存是有限制的

2.当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空间,比如回收一些不需要使用的对象、变量等

3.管理范围:任何继承了NSObject的对象,结其他基本数据类型(int、char、float、double、struct、enum等)无效

引用计数器

1.每个oc对象都有4个字节的空间用来存储引用计数器

2.每个OC对象都有自己的引用计数器,是一个整数,表示“对象被引用的次数”,即有多少人正在使用这个OC对象

引用计数器的作用

1.当使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认就是1

2.当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收,换句话说,如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收,除非整个程序已经退出。

引用计数器的操作

1.给对象发送一条retain消息,可以使引用计数器值+1(retain方法返回对象本身)

2.给对象发送一条release消息,可以使引用计数器值-1

3.可以给对象发送retainCount消息获得当前的引用计数器值

对象的销毁

1.当一个对象的引用计数器值为0时,那么它将被销毁,其占用的内存被系统回收

2.当一个对象被销毁时,系统会自动向对象发送一条dealloc消息

3.一般会重写dealloc方法,在这里释放相关资源,dealloc就像对象的遗言

4.一旦重写了dealloc方法,就必须调用[super dealloc],并且放在最后面调用

5.不要直接调用dealloc方法

6.一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃(即指针错误)

Xcode6找不到Use Automatic Reference Counting

手动关闭arc

新建项目完成后,点击左侧栏里的第一行,标题

这时主界面就会出现很多设置的项目。在上方有一个搜索栏。输入language或者ARC。

在搜索条件将Basic改为All,Combined改为Levels

然后找到Objective-C Automatic Reference Counting 设置为no

就可以使用release等代码了

野指针,指向已回收的对象(不可用内存地址)的指针

//EXC_BAD_ACCESS:访问了一块坏的内存(已经被回收不可用的内存)

打开僵尸对象检测开关:Edit schemes->Run debug->Diagnostics->Memory Management:Objective c Enable Zombie Objects

内存管理原则

1.原则分析

房间原理,只要房间还有人在用,就不会解散

只要还有人在用某个对象,那么这个对象就不会回收

只要你想用这个对象,就让对象的计数器+1

当你不再使用这个对象时,就让对象的计数器-1

当你换房间时,原来房间的对象计数器-1,新房间+1

2.原则规范

如果通过alloc、new或[mutable]copy来创建一个对象,那么必须调用release或 autorelease,不用自己创建的不用管

内存管理代码规范

1.只要调用了alloc,必须有release(autorelease),如果对象不是通过alloc产生的就不需要release

2.set方法的代码规范

1>基本数据类型:直接复制,无需内存管理

2>oc对象类型

- (void)setCar:(Car *)car

{

//1.他判断是不是新传进来对象

if(car!=_car)

{

//2.对旧对象做一次release

[_car release];

//3.对新对象做一次retain

_car = [car retain];

}

}

3.dealloc方法的代码规范

1>一定要[super dealloc],而且放到最后面

2>对self(当前)所拥有的其他对象做一次release

-(void)dealloc

{

[_car release];

[super dealloc];

}

如果调用了retain,无论这个对象是如何生成的,都需要调用release.

property

1.set方法内存管理相关的参数

retain:release旧值 ,retain新值(适用于OC对象类型)

assing:直接赋值(默认,适用于非OC对象类型)

copy:release旧值,copy新值(一般用于NSString)

2.是否要生成set方法

readwrite:同时生成setter和getter的声明、实现

readonly:只会生成getter的声明、实现

3.多线程管理

nonatomic:不加线程锁,性能高(ios一般就用这个)

atomic:加线程锁,性能低(默认)

4.setter和getter方法的名称

setter : 决定了set方法的名称,一定要有个冒号

getter : 决定了get方法的名称(一般用在BOOL类型的get方法,一般以is开头)

5.@property(getter = getWeight) int weight;

6.setHeight,height 同时生成setter和getter的声明、实现

7.@property (readwrite,assign) int height;

//不加锁性能高,直接赋值 age

8.@property (nonatomic,assign) int age;

//内存管理的name

9.@property (retain) NSString *name;

循环引用

当互相引用的时候,使用#import"类.h",类文件将会互相拷贝.

//而且为了提高编译效率,在头文件里并不需要类的全部内容,所以使用@class就足够了。

1.@class的作用:仅仅告诉编译器,某个名称是一个类

@class Person;//仅仅告诉编译器,Person是一个类

2.开发中引用一个类的规范

1>在.h文件中用@class来声明类

2>在.m文件中用#import来包含类的所有东西

3.@class和#import的区别

1> #import方式会包含类的所有信息,包括被引用类的变量和方法;

2> @class方式只是告诉编译器在A.h文件中B *b只是类的声明,具体这个类里有什么信息,这里不需要知道,等实现文件中真正要用到时,才会真正去查看B类中的信息

3>如果有上面个头文件都#import了同一个文件,或者这些文件依次被#import那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,这样的效率也是可想而知的,而相对来讲,使用@class方式就不会出现这种问题了

4>在.m实现文件中,如果需要引用到被引用类的实体变量或者方法时,还需要使用#import方式引入被引用类。

3.循环retain

1>比如A对象retain了B对象,B对象retain了A对象

2>这样会导致A对象和B对象永远无法释放

解决方案

当两端互相引用时,应该一端用retain,一端用assign

retain:release旧值 ,retain新值(适用于OC对象类型)

assing:直接赋值(默认,适用于非OC对象类型)

autorelease的基本用法

1.autorelease的基本用法

1>会将对象放到一个自动释放池中

2>当自动释放池被销毁时,会对池子里面的所有对象做一次release操作

3>会返回对象本身

4>调用完autorelease方法后,对象的计数器不变

2.autorelease的好处

1>不用再关心对象释放的时间

2>不用再关心什么时候调用release

3.autorelease的使用注意

1>占用内存较大的对象不要随便使用autorelease

2>占用内存较小的时象使用autorelease,没有太大影响

4.自动释放池

1>在ios程序运行过程中,会创建无数个池子。这些池子都是以栈结构存在(先进后出)

2>当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池

5.关于系统类

1>系统自带的方法里面没有包含alloc、new、copy,说明返回的对象都是autorelease的

比如不需要的NSString * str = [NSString stringWithFormatL@"age is %d",10];

比如需要的 NSNumber *num = [[NSNumber alloc]initWithInt:10];

[num release]

2>系统规范,方法名以类名开头。

3>OC不允许类同名,不像java可以用包来区别或c#的命名空间。

4>开发中经常会提供一些类方法,快速创建一个已经autorelease过的对象。

6.关于子类

1>如果在person中初始化时,固定初始化person那么,GoodPerson只能得到Person类对象,而如果指定为self那么谁来执行这个类方法以,就可以获得那个类的初始化

2>创建对象时,不要直接用类名,一般用self

例+ (id)person

{

return [[ss[self alloc]init] autorelease];

}

ARC

将非arc代码重构成arc代码:

Edit->

Refactor->Convert to Objective-C ARC ->next->save

使用第三方框架,可能不是arc的,就需要项目中,即需要arc,又可以不用arc

配置个别类,不使用arc:Xcode->s项目配置页,第一个页->Build Phases-类文件-回车或双击,弹出一个对话框,在对话框中输入-fno-bojc-arc

-fno-bojc-arc 不支持arc

-f-bojc-arc 支持arc

ARC判断准则:只要没有强指针指向对象,就会释放对象

ARC特点

1>不允许调用release、retain、retainCount

2>允许重写dealloc,但是不允许调用[super dealloc]

3>@property的参数

* strong : 成员变量是强指针(适用于OC对象类型)

* weak : 成员变量是弱指针(适用于OC对象类型)

* assign : 适用于非OC对象类型

4>使用ARC后,以前的retain改为strong其它一切不变

指针分2种:

1>强指针:默认情况下,所有的指针都是强针 __Strong

2>弱指针:只要没有强指针指向对象,对象被清空,如果对象被清空,弱指针被清空__weak

当指针p=nil时,对象没有指针指向而被释放

相当于,在检测到对象没有指针指向时,被[p release]

__strong Person *p = nil;

__weak Person *p = nil;

@property (nonatomic,strong) Dog *dog;

@property (nonatomic,weak) Dog *dog;

ARC机制下的,写法类似java

当两端循环引用的时候,解决方案:

1>ARC

1端用strong,另1端用weak

2>非ARC

1端用retain,另1端用assign

Person.h->

#import <Foundation/Foundation.h>

@interface Person : NSObject

@end


Person.m->

#import "Person.h"

@implementation Person
//当一个Person对象被回收时自动调用这个方法
- (void)dealloc
{

NSDate *currDate=[NSDate date];//先获取当前时间
//以下两行是创建一个格式化工具,先初始化一个时间格式,然后定义这个格式
NSDateFormatter *dateFormate=[[NSDateFormatter alloc]init];
[dateFormate setDateFormat:@"yyyy/MM/dd HH:mm:ss:SSS"];
//利用上面的时间格式工具把日期转换成字符串对象格式
NSString *dateStr=[dateFormate stringFromDate:currDate];

NSLog(@"Person 回收了 time:%@",dateStr);

//一定要调用父类的回收方法,而且要放在最后面
[super dealloc];
}
+ (void)load
{
NSDate *currDate=[NSDate date];//先获取当前时间
//以下两行是创建一个格式化工具,先初始化一个时间格式,然后定义这个格式
NSDateFormatter *dateFormate=[[NSDateFormatter alloc]init];
[dateFormate setDateFormat:@"yyyy/MM/dd HH:mm:ss:SSS"];
//利用上面的时间格式工具把日期转换成字符串对象格式
NSString *dateStr=[dateFormate stringFromDate:currDate];

NSLog(@"Person load time:%@",dateStr);
}
@end


main.m->

#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
//调用引用计数器 alloc计数器加1
Person *p = [[Person alloc]init];
//类型不匹配需要强转int a = (int),或是使用匹配类型NSInteger
int a = (int)[p retainCount];
NSInteger b =[p retainCount];
NSLog(@"p retainCount 1:%d,%ld",a,b);

//发送release引用计数器减一,减为零时,对象回收
//验证对象是否回收,重写-dealloc
// [p release];
//给对象发送一条retain消息,可以使引用计数器值+1(retain方法返回对象本身)
//当对象被回收时,再发送retain就不对了。
//retain计数器加1,返回对象本身
[p retain];
b =[p retainCount];
NSLog(@"p retainCount 2:%d,%ld",a,b);
[p release];
[p release];
//已回收后多次回收同样报错
//野指针,指向已回收的对象(不可用内存地址)的指针
//EXC_BAD_ACCESS:访问了一块坏的内存(已经被回收不可用的内存)
//[p release];
b =[p retainCount];
NSLog(@"p retainCount 3:%d,%ld",a,b);
//避免野指针的方法
//变成空指针,空指针指向nil,null,0
p = nil;
b =[p retainCount];
NSLog(@"p retainCount 4:%d,%ld",a,b);

//当p = nil;后 [p release]就不报错了,因为指针没有指向作何内存
//无效信息,oc没有空指针错误,给空指针发送消息不报错,仅仅是无效警告
[p release];
//打开僵尸对象检测开关:Edit schemes->Run debug->Diagnostics->Memory Management:Objective c Enable Zombie Objects

//打开僵尸对象检测开关后
// -[Person setAge:]:message sent to deallocated instance 0x100109a10
//给已经释放的对象发送了一条-setAge:消息;
//p.age=10;
}
return 0;
}


控制台:

2014-11-09 19:44:55.468 01引用计数器[869:303] Person load time:2014/11/09 19:44:55:461

2014-11-09 19:44:55.468 01引用计数器[869:303] Hello, World!

2014-11-09 19:44:55.469 01引用计数器[869:303] p retainCount 1:1,1

2014-11-09 19:44:55.470 01引用计数器[869:303] p retainCount 2:1,2

2014-11-09 19:44:55.471 01引用计数器[869:303] Person 回收了 time:2014/11/09 19:44:55:471

2014-11-09 19:44:55.471 01引用计数器[869:303] p retainCount 3:1,1

2014-11-09 19:44:55.472 01引用计数器[869:303] p retainCount 4:1,0

Person.h->

#import <Foundation/Foundation.h>
#import "Book.h"

@interface Person : NSObject
{
//当Book是成员变量时,Book无法继承Person
Book *_book;
}

- (void)setBook:(Book *)book;
- (Book *)book;
@end


Person.m->

#import "Person.h"
#import "Book.h"

@implementation Person
- (void)setBook:(Book *)book
{
//如果_book没有值,就直接retain如果有值,则将原先的release
//可以不加判断直接 release因为oc中空指针发消息不报错
if(_book!=nil){
[_book release];
}
_book = [book retain];
}
- (Book *)book
{
return _book;
}
- (void)dealloc
{
//对象回收前将所持有的资源处理
[_book release];

NSLog(@"Person dealloc");
[super dealloc];
}
@end


Book.h->

#import <Foundation/Foundation.h>

@interface Book : NSObject

@end


Book.m->

#import "Book.h"

@implementation Book
- (void)dealloc
{

NSLog(@"Book dealloc");
[super dealloc];
}
@end


main.m->

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Book.h"

int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
//p计数器加1
Person *p = [[Person alloc]init];

//b,b2计数器加1
Book *b = [[Book alloc]init];
Book *b2 = [[Book alloc]init];

NSInteger i = [p retainCount];
NSLog(@"p retainCount:%ld",i);

//p调用b b计数器+1
p.book = b;

i = [b retainCount];
NSLog(@"b retainCount:%ld",i);

//p调用b2,b-1 ,b2+1
p.book = b2;

i = [b retainCount];

NSInteger i2 = [b2 retainCount];
NSLog(@"b:%ld,b2 retainCount:%ld",i,i2);

[b release];
b = nil;

[b2 release];
b2 = nil;

//计数器减1
[p release];
p=nil;
}
return 0;
}


控制台:

2014-11-09 23:15:57.816 02多对象内存管理[1401:303] Hello, World!

2014-11-09 23:15:57.819 02多对象内存管理[1401:303] p retainCount:1

2014-11-09 23:15:57.820 02多对象内存管理[1401:303] b retainCount:2

2014-11-09 23:15:57.820 02多对象内存管理[1401:303] b:1,b2 retainCount:2

2014-11-09 23:15:57.821 02多对象内存管理[1401:303] Book dealloc

2014-11-09 23:15:57.821 02多对象内存管理[1401:303] Book dealloc

2014-11-09 23:15:57.822 02多对象内存管理[1401:303] Person dealloc

Person.h->

#import <Foundation/Foundation.h>
#import "Car.h"

@interface Person : NSObject
{
int _age;
Car * _car;
}
- (void)setAge:(int)age;
- (int)age;

- (void)setCar:(Car *)car;
- (Car *)car;
@end


Person.m->

#import "Person.h"

@implementation Person

- (void)setAge:(int)age
{
//基础数据类型不需要管理内存
_age = age;
}
- (int)age
{
return _age;
}

- (void)setCar:(Car *)car
{
//因为p的车_car和c1相同,而p在setCar中又release所以 c1-1,而之后的retain便不可用了。因为内存无效
//p.car = c1;
//解决办法在p setCar中判断如果新车与旧车是同一款,则不进行操作

if(_car!=car){

//因为oc空指针发消息不报错,所以不用判断,直接发回收信息
[_car release];
//将新车赋给人
_car = [car retain];

}
}
- (Car *)car
{
return _car;
}
- (void)dealloc
{
//回收所拥有的车
[_car release];
NSLog(@"age:%d of Person dealloc",_age);
[super dealloc];
}
@end


Car.h->

#import <Foundation/Foundation.h>

@interface Car : NSObject
{
int _speed;
}
- (void)setSpeed:(int)speed;
- (int)speed;
@end


Car.m->

#import "Car.h"

@implementation Car

- (void)setSpeed:(int)speed
{
//基础数据类型不需要管理内存
_speed = speed;
}
- (int)speed
{
return _speed;
}
- (void)dealloc
{

NSLog(@"speed:%d of Car dealloc",_speed);
[super dealloc];
}
@end


main.m->

//
//  main.m
//  03set方法内存管理
//
//  Created by Whome on 14-11-9.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Car.h"
/*
内存管理代码规范
1.只要调用了alloc,必须有release(autorelease),如果对象不是通过alloc产生的就不需要release
2.set方法的代码规范
1>基本数据类型:直接复制,无需内存管理
2>oc对象类型
- (void)setCar:(Car *)car
{
//1.他判断是不是新传进来对象
if(car!=_car)
{
//2.对旧对象做一次release
[_car release];
//3.对新对象做一次retain
_car = [car retain];
}
}
3.dealloc方法的代码规范
1>一定要[super dealloc],而且放到最后面
2>对self(当前)所拥有的其他对象做一次release
-(void)dealloc
{
[_car release];
[super dealloc];
}
*/
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
//年龄为20的人 p-1
Person *p = [[Person alloc]init];
p.age =20;
//速度为70的车 c-1
Car *c = [[Car alloc]init];
c.speed = 70;
//速度为100的车 c1-1
Car *c1 = [[Car alloc]init];
c1.speed = 100;
//年龄20的人有了速度70的人 c-2
p.car = c;
//年龄20的人有了速度100的人 c-1 c1-2
p.car = c1;

//一个不严谨的写法
// c1-1
//[c1 release];

//因为p的车_car和c1相同,而p在setCar中又release所以 c1-1,而之后的retain便不可用了。因为内存无效
//p.car = c1;

//解决办法在p setCar中判断如果新车与旧车是同一款,则不进行操作

[p release];

[c release];

[c1 release];

}
return 0;
}


控制台:

2014-11-10 06:12:56.265 03set方法内存管理[458:303] Hello, World!

2014-11-10 06:12:56.269 03set方法内存管理[458:303] age:20 of Person dealloc

2014-11-10 06:12:56.270 03set方法内存管理[458:303] speed:70 of Car dealloc

2014-11-10 06:12:56.271 03set方法内存管理[458:303] speed:100 of Car dealloc

Person.h->

#import <Foundation/Foundation.h>
#import "Book.h"

/*
1.set方法内存管理相关的参数
retain:release旧值 ,retain新值(适用于OC
对象类型)
assing:直接赋值(默认,适用于非OC对象类型
)
copy:release旧值,copy新值

2.是否要生成set方法
readwrite:同时生成setter和getter的声明、实
现
readonly:只会生成getter的声明、实现

3.多线程管理
nonatomic:不加线程锁,性能高(ios一般就用这
个)
atomic:加线程锁,性能低(默认)

4.setter和getter方法的名称
setter : 决定了set方法的名称,一定要有个冒
号
getter : 决定了get方法的名称(一般用在BOOL
类型的get方法,一般以is开头)

*/

@interface Person : NSObject

//(retain):相当于会在set方法中release旧值,retain新值
//缺点dealloc还是需要手写
@property(retain)Book *book;
//返回BOOL类型的方法一般以is开头
@property (getter=isRich) BOOL rich;
//getter名为getW,setter名为setW
@property(getter = ss,setter = qwerq:) int weight;
//setHeight,height 同时生成setter和getter的声明、实现
@property (readwrite,assign) int height;
//不加锁性能高,直接赋值 age
@property (nonatomic,assign) int age;
//内存管理的name
@property (retain) NSString *name;

@end


Person.m->

#import "Person.h"

@implementation Person
/*
@property(retain)Book *book;
等同于
- (void)setBook:(Book *)book
{
if(_book!=book){

[_book release];
_book = [book retain];

}
}
- (Book *)book
{
return _book;
}
*/
- (void)dealloc
{
//回收所拥有的书
[_book release];
NSLog(@"Person dealloc");
[super dealloc];
}
@end

Book.h->

#import <Foundation/Foundation.h> @interface Book : NSObject @end

Book.m->

#import "Book.h"

@implementation Book

- (void)dealloc
{

NSLog(@"Book dealloc");
[super dealloc];
}
@end


main.m->

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Book.h"

int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
Person *p = [[Person alloc]init];
Book *b = [[Book alloc]init];

p.book = b;
NSInteger i = [b retainCount];
//p.qwerq不好使
[p qwerq:100];
p.age = 0;
p.rich = 1;
NSLog(@"age:%d,rich=%d weight:%d i:%ld",p.age,p.isRich,p.ss,i);
[p release];
p = nil;
[b release];
b = nil;
}
return 0;
}


控制台:

2014-11-10 08:22:26.994 04set方法_property[708:303] Hello, World!

2014-11-10 08:22:27.000 04set方法_property[708:303] age:0,rich=1 weight:100 i:2

2014-11-10 08:22:27.001 04set方法_property[708:303] Person dealloc

2014-11-10 08:22:27.003 04set方法_property[708:303] Book dealloc

Person.h->

#import <Foundation/Foundation.h>

//仅标明Card是一个类
@class Card;
@interface Person : NSObject

//retain:release旧值 ,retain新值(适用于OC对象类型)
@property (nonatomic,retain) Card *card;

@end


Person.m->

#import "Person.h"
#import "Card.h"

@implementation Person

+ (void)initialize
{
NSLog(@"initalize Person");
}

+ (void)load
{
NSLog(@"load Person");
}

- (void)dealloc
{

[_card release];

NSLog(@"dealloc Person");

[super dealloc];
}

@end


Card.h->

#import <Foundation/Foundation.h>

//仅标明Person是一个类
@class Person;
@interface Card : NSObject

//assing:直接赋值(默认,适用于非OC对象类型)
@property (nonatomic,assign) Person *person;

@end


Card.m->

#import "Card.h"
#import "Person.h"

@implementation Card

+ (void)initialize
{
NSLog(@"initalize Card");
}

+ (void)load
{
NSLog(@"load Card");
}

- (void)dealloc
{

[_person release];

NSLog(@"dealloc Card");

[super dealloc];
}
@end


main.m->

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Card.h"

/*

循环retain
1>比如A对象retain了B对象,B对象retain了A对象
2>这样会导致A对象和B对象永远无法释放

解决方案
当两端互相引用时,应该一端用retain,一端用assign

*/

int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");

//p-1
Person *p = [[Person alloc]init];
//c-1
Card *c = [[Card alloc]init];
//c-2
p.card = c;
//p-1
c.person = p;

//c-1
[c release];

//p-0 c-0

[p release];
}
return 0;
}


控制台:

2014-11-11 04:07:22.155 05循环引用[388:303] load Person

2014-11-11 04:07:22.159 05循环引用[388:303] load Card

2014-11-11 04:07:22.159 05循环引用[388:303] Hello, World!

2014-11-11 04:07:22.160 05循环引用[388:303] initalize Person

2014-11-11 04:07:22.160 05循环引用[388:303] initalize Card

2014-11-11 04:07:22.161 05循环引用[388:303] dealloc Card

2014-11-11 04:07:22.161 05循环引用[388:303] dealloc Person

Person.h->

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (nonatomic,assign) int age;

//简化类初始化写法
+ (id)person;
//初始化并给成员变量赋值
+ (id)personWithAge:(int)age;
@end


Person.m->

#import "Person.h"

@implementation Person
- (void)dealloc
{
NSLog(@"age:%d Person dealloc",_age);
[super dealloc];
}
//简化类初始化写法
+ (id)person
{
//如果在person中初始化时,固定初始化person那么,GoodPerson只能得到Person类对象,而如果指定为self那么谁来执行这个类方法以,就可以获得那个类的初始化
return [[[self alloc]init]autorelease];
}
//初始化并给成员变量赋值
+ (id)personWithAge:(int)age
{
Person *p = [self person];
p.age = age;
return p;
}
@end


GoodPerson.h->

#import "Person.h"

@interface GoodPerson : Person
@property (nonatomic,assign) int money;
@end


GoodPerson.m->

#import "GoodPerson.h"

@implementation GoodPerson
- (void)dealloc
{
NSLog(@"money:%d GoodPerson dealloc",_money);
[super dealloc];
}
@end


main.m->

#import <Foundation/Foundation.h>
#import "Person.h"
#import "GoodPerson.h"

/*
autorelease方法会返回对象本身
调用完autorelease方法后,对象的计数器不变
autorelease会将对象放到一个自动释放池中
当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
*/
int main(int argc, const char * argv[]) {

//一个内存栈,一般存放占用内存较小的对象
//声明这个代码块是一个自动释放池,当自动释放池销毁时,autorelease的对象将被release
@autoreleasepool
{//{开始代表创建了释放池
Person *p1 = [[[Person alloc]init]autorelease];
p1.age = 20;
}//}结束代表销毁释放池

//自动释放池的其它写法
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
Person *pp = [[[Person alloc]init]autorelease];
pp.age = 100;
[pool release];

//将池子清空
//[pool drain];

//简化类初始化写法,初始化成员变量,栈先进后出
@autoreleasepool {
Person *pw = [Person person];
pw.age = 101;

Person *pw1 = [Person personWithAge:102];
}

//常用错误
//1.没有放在@autoreleasepool{}中是无法调用release的
Person *p2 = [[[Person alloc]init]autorelease];
p2.age = 10;

//2.发送了两次autorelease,当池销毁时,也会发送两次release,但是在上一次的时候,已经变成野指针了,所以无效
//    @autoreleasepool
//    {
//        Person *p3 = [[[[Person alloc]init]autorelease] autorelease];
//    }

//2.当p4发送release后,p4已经成为野指针了,而当池子销毁时,会再一次发送release所以无效。
//    @autoreleasepool
//    {
//        Person *p4 = [[[Person alloc]init]autorelease];
//
//        [p4 release];
//    }

//关于子类细节
@autoreleasepool {

//如果在person中初始化时,固定初始化person那么,GoodPerson只能得到Person类对象,而如果指定为self那么谁来执行这个类方法以,就可以获得那个类的初始化
GoodPerson *gp = [GoodPerson personWithAge:103];
// '-[Person setMoney:]: unrecognized selector sent to instance 0x100603970'
gp.money = 10;
}

return 0;
}


控制台:

2014-11-11 08:37:58.637 06-autorelease[565:303] age:20 Person dealloc

2014-11-11 08:37:58.639 06-autorelease[565:303] age:100 Person dealloc

2014-11-11 08:37:58.640 06-autorelease[565:303] age:102 Person dealloc

2014-11-11 08:37:58.641 06-autorelease[565:303] age:101 Person dealloc

2014-11-11 08:37:58.642 06-autorelease[565:303] money:10 GoodPerson dealloc

2014-11-11 08:37:58.643 06-autorelease[565:303] age:103 Person dealloc

Program ended with exit code: 0

Person.h->

#import <Foundation/Foundation.h>

@class Dog;

@interface Person : NSObject

//强指针
@property (nonatomic,strong) Dog *dog;

@end


Person.m->

#import "Person.h"

@implementation Person

- (void)dealloc
{
NSLog(@"Person dealloc");
//ARC不允许,调用父类的dealloc
//[super dealloc];
}

@end


Dog.h->

#import <Foundation/Foundation.h>

@class Person;

@interface Dog : NSObject

//强指针
@property (nonatomic,strong) Person *person;

@end


Dog.m->

#import "Dog.h"

@implementation Dog

- (void)dealloc
{
NSLog(@"Dog dealloc");
}

@end


main.m->

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Dog.h"
/*
 
 ARC判断准则:只要没有强指针指向对象,就会释放对象
 
 ARC特点
 1>不允许调用release、retain、retainCount
 2>允许重写dealloc,但是不允许调用[super dealloc]
 3>@property的参数
 * strong : 成员变量是强指针(适用于OC对象类型)
 * weak   : 成员变量是弱指针(适用于OC对象类型)
 * assign : 适用于非OC对象类型
 4>使用ARC后,以前的retain改为strong其它一 切不变

 
 指针分2种:
 1>强指针:默认情况下,所有的指针都是强针 __Strong
 2>弱指针:只要没有强指针指向对象,对象被清空 ,如果对象被清空,弱指针被清空__weak
 
 当指针p=nil时,对象没有指针指向而被释放相当于,在检测到对象没有指针指向时,被[p release]
 
 __strong Person *p = nil;
 
 __weak Person *p = nil;
 
 ARC机制下的,写法类似java

 */

int main(int argc, const char * argv[]) {
    
    //强指针,默认强指针
    __strong Person *p = [[Person alloc]init];
    NSLog(@"p:%@",p);
    
    //弱指针
    __weak Person *p2 =p;
    
    NSLog(@"p2-1:%@",p2);
    
    p = nil;
    p2 = nil;
    
    //错误写法,因为没有强指针指向类对象,类对象不会存在,类对象不存在,指向类对象的弱指针也会被清空
    p2 = [[Person alloc]init];
    
    NSLog(@"p2-2:%@",p2);

    p = [[Person alloc]init];
    
    Dog *d = [[Dog alloc]init];
    
    p.dog = d;
    
    NSLog(@"p.dog-1:%@",p.dog);
    
    d = nil;
    
    p.dog = d;
    
    NSLog(@"p.dog-2:%@",p.dog);
    
    //arc的循环引用
    //因为都是强指针,所以会导至无法释放,解决办法,将其中d.person变为弱指针,即人不存在了,指针无聊。
    p = [[Person alloc]init];
    d = [[Dog alloc]init];
    
    p.dog = d;
    d.person = p;
    
    /*
     当main结束时首先销毁d,然后销毁p,然后人和狗的类还存在,它们互相强指针,所以都没释放,但是如果将其中一个弱指针,那么被弱指针指向的类对象,就可以被销毁,它的强指针成员也就不存在,那么那个拥有弱指针成员的类对象也就被销毁
     */

    
    return 0;
}


控制台:

2014-11-11 23:20:01.803 07ARC[627:303] p:<Person: 0x100601a80>

2014-11-11 23:20:01.805 07ARC[627:303] p2-1:<Person: 0x100601a80>

2014-11-11 23:20:01.805 07ARC[627:303] Person dealloc

2014-11-11 23:20:01.806 07ARC[627:303] Person dealloc

2014-11-11 23:20:01.806 07ARC[627:303] p2-2:(null)

2014-11-11 23:20:01.807 07ARC[627:303] p.dog-1:<Dog: 0x1001042f0>

2014-11-11 23:20:01.807 07ARC[627:303] Dog dealloc

2014-11-11 23:20:01.808 07ARC[627:303] p.dog-2:(null)

2014-11-11 23:20:01.809 07ARC[627:303] Person dealloc

Program ended with exit code: 0

[align=center]------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------[/align]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: