黑马程序员---成长之路-----OC之基础篇MRC内存管理

------<a href="http://www.itheima.com"target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流

                                                                                                         MRC内存管理

MRC内存管理:我认为其实就是手动管理堆区的内存空间。


对象在堆区的空间:


<span style="font-size:14px;">#import<Foundation/foundation.h>
#import "Dog.h"


int main(){


@autoreleasepool{


              //创建一个对象
              //对象创建完成以后,默认的所有者有一个,所以引用计数为一
              Dog *byb=[Dog new];//1


               [byd eat];
              NSLog(@"byd.retainCount=%lu",byd.retainCount);
              //如果一个对象已经被释放了,这个对象就称位僵尸对象
              [byd release];//0
               


              //这句话默认不报错,开启僵尸检查才报错
             [byd eat];//这就是使用僵尸对象调用方法,这个时候byd也就称为野指针
             //野指针其实就是被释放了空间的指针
             //对象只要变成僵尸对象就不能用了,必须重新申请才能用
              
          }

}</span>




避免使用僵尸对象  : 




<pre name="code" class="objc"><span style="font-size:14px;">#import<Foundation/foundation.h>
#import "Dog.h"

int main(){

@autoreleasepool{

        Dog *d=[[Dog alloc] init];//1
        [d release];//0


        //
         //[d retain]想让d起死回生,开启僵尸对象检测的话会报错

         避免使用僵尸对象的方法是,对象释放后了以后,给对象赋值为nil
         d=nil;
         [d retain]//僵尸对象使用不会报错了(开启僵尸检测的情况下)

                  }
}</span>

 




单个对象的内存泄露问题


<span style="font-size:14px;">#import<Foundation/foundation.h>
#import "Dog.h"


int main(){


@autoreleasepool{


             //内存泄露情况
             //创建完成使用后没有release
             Dog *d=[[Dog alloc] init];//}
              //retain完之后没有release
                [d retain];//2

                [d release];//1

             //不当的使用nil
             Dog *d=[[Dog alloc] init];

             d=nil;
             [d eat];
              [d release];  


                   }
             return 0;
}
</span>



引用计数器:
  用来保存当前对象有几个东西在使用它(数字)
引用计数器的作用:
  用来判断对象是否应该回收内存空间(如果对象不等于nil,当引用
 计数器为0,此时要回收对象的内存空间)
引用计数器的操作:
  retain  使得引用计数器+1
  release 使得引用计数器-1
  retainCount  得到引用计数器的值


如果一个对象被释放的时候,会有“临终遗言”(会调用该对象的dealloc方法)
注意:
   dealloc方法是NSObject的,一般我们要重写dealloc方法
    在dealloc方法的内部,要调用[super dealloc];


手动内存管理:
MRC手动内存管理
ARC自动内存管理


注意:
  我们创建一个项目,此时默认的是ARC(自动内存管理)
  把项目从ARC模式改成MRC模式


dealloc方法是对象的临终遗言的方法
对象被撤销的时候,会默认的调用该方法(此方法可以重写,但是不要在main函数中出现)


内存管理:

对象如果不在使用了,就应该回收它的空间防止造成内存泄露。
内存管理的范围:
所有的集成了NSObject的对象的内存管理
基本数据类型(C语言中的数据类型就称为基本数据类型)的数据内存
不需要我们管理
内存管理的原则:
一、
如果对象有人使用,就不应该收回
如果你想使用这个对象,应该让这个对象retain一次
如果不想使用这个对象,应该让这个对象relase一次
二、
谁创建 谁release
三、
谁retain       谁release


内存管理研究的内容:
一、野指针
定义的指针变量没有初始化
指向的空间已经被释放了
二、内存泄露
{
Person *p=[Person new];
}
p栈区  
[Person new]; 堆区
如果栈区的p已经释放了,而堆区的空间还没有释放,堆区的空间就被泄露了


set方法内存管理
set方法的写法:
判断_car存放的释放是形参对象,如果不是,则执行[_car release];
<span style="font-size:14px;">if(_car!=car){


 [_car release];//先释放上一个对象,(注意第一次是向nil发送release消息)


 _car=[car retain];

             }
}</span>




上诉判断是一个固定写法!
基本数据类型的数据作为实例变量
int _speed;
set方法的写法
<span style="font-size:14px;">-(void)setSpeed:(int)speed{
   _speed=speed;

}
Dog* _dog;


//对于对象作为另外一个类的实例变量
-(void)setDog:(Dog*)dog{


//判断对象是否是原来的对象
if(_dog!=dog){
//release旧值
[_dog release];
//retain 新的值并且赋值给实例变量
_dog=[dog retain];
     }
}</span>




@porperty参数
格式:@porperty(参数1,参数2) 数据类型 方法名
参数类别     参数                                 说明
原子性            atomic                 对属性枷锁,多线程下线程安全,默认值
                        nonatomic          对属性不枷锁,多线程下不安全,但是速度快
读写属性        readwrete          生成getter、setter,默认值
                        readonly            只生成getter方法
set方法处理  assign                直接赋值,默认值
                       retain                  先release原来的值,再retain新值
                       copy                   先release原来的值,再copy新值


先看set方法中:
什么时候使用retain(实用于OC对象)
在一个类中有关联其他对象的时候,这个对象的@property(nonatomic,retain)
什么时候使用assign
实例变量是剧本数据类型的时候(实用与非OC对象)


set和get名称:
<span style="font-size:14px;">@property(nonatomic,assig,setter=isVip:)BOOL Vip;


Person *p=[Person new];
p.vip=YES;//替换set方法@property(nonatomic ,setter=isVip:)  [p isVip:YES];
if(p.vip){
    NSLog(@"是Vip");


          }</span>




@class的使用
 使用格式:
@class 类名;
@class xxx;


含义:告诉编译器,xxx是一个类,至于类有哪些属性和方法,此处不去检查
好处:如果xxx文件内容发生了改变,而不需要重新编译
@class的使用注意:
1、.h  @class  xx
2、.m  #import "xx.h"


@class的特殊用法:可以解决循环引入问题(比如A中用import引入B,B中
用import引入A时会报错,这样就可以用@class解决问题,就不会报错)。
在.h中相互交叉引入#import会报错,但是在.m中相互引用不会报错


循环retain问题
循环retain的使用:
循环的retain会导致两个对象都会内存泄露
防止方法:
1、让某个对象多释放一次
2、一端使用assugn一端使用retain
示例:
Person.h
引入头文件时必须用@class
<span style="font-size:14px;">@property(nonatomic,retain)Person *owner;
Dog.m
-(void)dealloc{


    [_owner release];
    NSLog(@"Dog已经挂啦") ;
    [super dealloc];
       


}</span>




Dog.h
引入头文件时必须用class
<span style="font-size:14px;">@property(nonatomic,retain)Person *owner;
Dog.m
-(void)dealloc{


    [_owner release];
    NSLog(@"Dog已经挂啦") ;
    [super dealloc];
       


}</span>




<span style="font-size:14px;">int main(){


     Person  *p=[Person new];
      Dog *d=[Dog new];




      p.dog=d;
      d.owner=p;
    


      [p release];
      [d release];
}</span>


这就会造成内存泄露。像上面那样改变就好了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值