IOS学习---OC基础学习5

内存管理:
栈中存储的数据 在执行至作用域之外的时候自动释放
堆空间中存储的数据需要手动释放
栈空间:一般存储变量,指针(Person *p)
堆空间:对象(Person)

引用计数器:
表示 对象被引用的次数 是一个整数 每个对象都有自己的引用计数器 每个对象内部都会分配4个字节来存储。
计数器 初始值为1
作用:
1、当使用alloc new copy创建一个新对象时,新对象的引用计数器默认为1
2、当一个对象的引用计数器值为0零对象占用的内存就会被系统回收,换句换说,如果对象的计数器部位0,那么在整个运行过程中,它占用的内存就不可能被回收,除非整个程序已经退出
计数器操作:
1、当对象发送retain消息(调用retain方法),可以使引用计数器+1(retain方法放回对象本身)
2、给对象发送一条release消息,可以使引用计数器的值-1
3、可以给对象发送retainCount消息获得当前的引用计数器值
对象的销毁:
1、当一个对象的引用计数器为0时 那么它将被销毁,其占用的内存将被系统回收
2、当一个对象销毁时 系统会自动向对象发送一条dealloc消息
一般会重写dealloc方法,在这里释放相关资源,dealloc就像对象的遗言
3、一旦重写了dealloc方法,就必须调用[super dealloc],并且放在最后面调用
4、不要直接调用dealloc方法

具体实例:
Person *p = [[Person alloc] init];
NSUInteger c = [p retainCount];
NSLog(@"计数器:%ld",c)

[p retain];//retain 返回的是对象的本身 是计数器+1
[p release];//计数器-1


//当一个Person对象被回收的时候,就会自动调这些
- (void)dealloc
{
NSLog(@"对象被回收");
//super的dealloc一定要调用,而且放在最后
[super dealloc];
}

野指针:
当一个对象的计数器为零,就会被内存回收内存空间,就变成了一个不可用的对象,也称为僵尸对象 指向僵尸对象(不可用类)的指针也称为野指针。
经典错误:
EXC_BAD_ACCESS(code-1,address-ox20)
意思:访问了一块坏的地址(0x20) 该地址可能由于计数器为零已经被内存回收,已经不可用的内存  
也可以称为 野指针错误(指针指向了一个不存在的地址)


清空指针:
一旦知道类的内存被回收,就应该清空指针,具体操作为:
p = nil;
OC不存在空指针错误,给空指针发送消息不报错
message sent to deallocated instance
给已经释放的对象放松一条setAge消息

总结:
1、retain、release方法的基本使用
①retain:计数器+1 方法是由返回值的 其返回值为 对象本身
②release:计数器-1
③retainCount:返回计数器当前值
④dealloc:
   *当一个对象要被回收的时候会调用
   *一定要调用[super dealloc],并且放在最后面
2、概念
野指针 :指向僵尸对象(内存不可用)的指针,给野指针发送消息会报错(EXC_BAD_ACCESS(code-1,address-ox20))
僵尸对象:所占用的内存已经被回收的对象,僵尸对象不能再被使用
空指针:没有指向任何东西的指针(存储的东西是 nil,NULL,0),给空指针发送消息不会报错


内存管理原则:
1、只要还有人在用某个对象,那么这个对象就不可能被回收
2、只要你想使用这个对象,就让对象的计数器+1
3、只要不想使用这个对象,就让对象的计数器-1

谁创建 谁release
1、如果你通过alloc new 或者[mutable]copy来创建一个对象,那么你必须调用release或者autorelease来释放
2、不是你创建的 就不用你去autorelease

谁retain 谁release
只要你调用了retain 无论这个对象如何生成的,你都要调用release


总结:
有始有终,有加就有减
曾经让对象计数器+1,就必须在最后让对象计数器-1

多个对象之间的内存管理(程序):

总结:
1、你想使用某个对象,就应该让该对象的计数器+1即做一次(retain)操作
2、你不想在使用(占用)某个对象,就应该让对象的计数器-1(让对象做一次release)
3、谁retain 谁release
4、谁alloc 谁release 

set方法的内存管理:
总结:
内存管理的代码规范:
1、只要调用alloc必须有release(autorelease),对象不是由alloc产生的就不需要release
2、set方法代码规范
①基本数据类型:直接复制  _age = age;
- (void)setAge:(int)age
{
_age = age;
}
②OC对象类型
- (void)setCar(Car*)car
{
//先判断是否为新传进来的对象
if(car != _car)
{
[_car release];//释放原来拥有的car
//对新对象做一次retain
_car = [car retain];
}
}

③dealloc方法代码规范
  1、一定要[super dealloc] 而且放到最后
  2、对self(当前)所拥有的其他对象做一次release
  3、- (void)dealloc
    {
//首先对原来拥有的对象做一次release
[self release];
NSLog(@"释放xxx对象");
[super dealloc];
    }

想要声明某个对象属性
@property (retain) Book *book;
在dealloc中加入 [_book release];
通过这两个就可以省略掉那些重写set方法的问题

@propert
1、set方法内存管理相关的参数
 *retain : release旧值 retain 新值(适用于OC对象类型)
 例子@property (retain) Book *book;
 例子:@property (assign) int age
 *assign:直接赋值(默认:适用于非OC对象类型)
 

 *copy:release旧值 copy新值


2、是否要生成set方法
@property (readwrite)int age同时生成setter和getter方法
@property (readonly) int age   只生成getter方法
@property (readwrite assign int age 默认set和get方法都生成默认为readwrite

3、多线程管理
 *nonatomic:性能高(一般用这个)
 *atomic:性能低(默认)


4、setter和getter方法的名称
@property  int age;
默认的setter方法名为:setAge:
默认的getter方法名为:age


如果想修改这两个方法的方法名 可使用
@property (getter = getAge)int age;


此时 getter方法的方法名为getAge
@property (setter = setAbc:)int age;(一定要有冒号)


修改方法名称的问题一般用在布尔类型中,且只修改getter方法 因为一般的布尔类型以is开头 isRich


循环引用:
若程序中存在下面的状况:
两个类 一个身份证类 一个Person类  两者是一一对应的关系
但是如果在 Card类中import Person类 在Person类中import card类就会出现错误 此时只需要在 将原来的import语句改写为:@class +类名  标明 这个名字表示一个类即可

总结:
1、@class的作用:仅仅告诉编译器 某个名称是一个类
   例子:@class Person 表示Person是一个类
2、开发中引用一个类的规范
  ①:在.h文件中用@class来声明类
  ②:在.m文件中用#import来包含类的所有东西

#import的缺点:
假设 card类被其他100个类引用这
#import "card.h" 
若card.h文件修改一次,那么着其他所有类需要充新拷贝 降低编译效率
因此 在.h文件夹中使用@class  在.m文件夹中使用#import
@class与#import的区别:
1、#import方式会包含被引用类的所有信息,包括被引用类的变量和方法;@class方式只是告诉编译器在A.h文件中 B *b只是一个类的声明,具体这个类里有什么信息,这里不需要知道,等实现文件中真正要用到时,才会真正去查看B类中信息
2、如果有上百个头文件都#import了同一个文件,或者这些文件依次被#import 那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,这样的效率也是可想而知,而相对来讲使用@class方式就不会出现这种问题
3、在.m实现文件中,如果需要饮用到被引用类的尸体变量或者方法时,还需要使用#import方式引入被引用类
 
两端循环引用的解决方案(人和身份证问题):
1、一端用retain 
2、一端用 assign

autorelease:半自动释放
autorelease方法会返回对象本身
autorelease 会将对象放到一个自动释放池中
当自动释放池销毁时,会对池子里面的所有对象做一次release操作
Person *p = [[[Person alloc] init] autorelease];;
调用玩autorelease方法后,对象的计数器不变
缺点:不能准确释放控制释放内存的时间 比较适用于占用内存较小的对象

@autoreleasepool{//开始代表创建了释放池

}//结束代表销毁释放池

autorelease基本用法:
1、autorelease 会将对象放到一个自动释放池中
2、当自动释放池销毁时,会对池子里面的所有对象做一次release操作
3、autorelease方法会返回对象本身
4、调用autorelease方法后,对象的计数器不变
autorelease的优点:
1、不用再关心对象释放的时间
2、不用再关心什么时候调用release
autorelease的缺点
1、占用内存较大的对象不要随便使用autorelease 释放池持续时间较长 延迟释放时间 比较费内存
2、占用内存较小的对象使用autorelease没太大的影响
autorelease的错误写法:
1、alloc之后调用autorelease,有调用release
@autoreleasepool{
Person *p1 = [[[Person alloc] init] autorelease];
[p1 release];
}
2、连续多次调用autorelease
@autoreleasepool{
Person *p1 = [[[[Person alloc] init] autorelease] autorelease];
}
自动释放池:
1、IOS程序运行过程中,会先创建无数个池子,这些池子都是以栈结构存在(后进先出)
2、当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池
自动释放池的创建方式:
1、用于IOS5.0之前
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[pool release];
2、IOS5.0之后
@autorepool{
}
autorelease小练习
1、利用类方法简写程序
原来的程序:
Person *p = [[[Person alloc] init] autorelease];
p.age =10
可以通过改写:
1、通过书写类方法 简化第一句等号后面的代码
在.m中添加类方法;
+(id)person
{
return [[[Person alloc] init] autorelease];
}
则源程序可改写为:
Person *p = [Person person]; 使用类 来调用各类方法 
2、丰富类方法person
+(id)personWithAge:(int)age
{
Person *p = [[[Person alloc] init] autorelease];
p.age = age;
return p;
}
那么 原程序可以改写为
Person *p = [Person personWithAge:10];
设计这些方法的时候都要以类名开头

注意:
1、系统自带的方法里面没有包含alloc new copy,说明返回的对象都是autorelease的
2、开发中经常会提供一些类方法,快速创建一个已经autorelease过的对象
3、创建对象时 不要直接用类名一般用self 优点是如果子类调用父类的方法,仍然是生成一个子类的对象而不会生成父类对象进而产生其他错误
+ (id)person
{
return [[[self alloc] init] autorelease];
}

今日学习总结:
一、计数器的基本操作
1、retain:+1
2、release:-1
3、retainCount:获取计数器


二、set方法的内存管理
1、set 方法的实现
- (void) setCar:(Car*)car
{
if(_car != car)
{
[_car release];
_car = [car retain];
}
}
2、dealloc方法实现 当计数器为0时系统自动调用不用手动调动
- (void)dealloc
{
//先释放他拥有的其他对象,比如它拥有一台车
[_car release];

[super release];
}

三、@property参数
1、OC对象类型
@property (nonatomic,retain)类名*属性名
@property (nonatomic,retain) Car *car
2、非OC对象类型(基本数据类型)
@property (nonatomic,assign)类型名称 属性名
@property (nonatomic,assign) int age;
注意:被retain过的属性,必须在dealloc方法中release属性

四、autorelease
1、系统自带的方法中,如果不包含alloc、new、copy 那么这些方法返回的对象都是已经autorelease过的
[NSString stringWithFormat:.....];
[NSDate date]
2、开发中经常写一些类方法,快速创建一个autorelease的对象
   *创建对象的时候不要直接使用雷鸣,用self
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值