黑马程序员-OC内存管理

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

(一)手动管理内存

栈:存放局部变量(所占用内存会自动销毁) -> 指向堆空间

堆:存放对象(所占用内存需手动销毁)

管理范围:所有继承NSObject的类对象


1.内存泄露?内存泄露的后果?

_age = [age ratain];

自己申请的内存,没有释放 会使内存中存在很多的垃圾,浪费不必要的内存

2.应用计数器:用于计算对象被使用的次数,是一个整数(每个对象都有自己的引用计数器:占4个字节) 

(1)当使用alloc、new或copy创建新对象时,新对象的引用计数器被设置为1.

(2)当引用计数器为0时,则此对象所占用内存就会被回收。(发送release消息时,计数器减1)

(3)给对象发送retainCount消息获取当前的计数器值

   注:retain方法返回的是对象本身(有返回值)

3.对象的销毁
(1)引用计数器为0,对象占用的内存被系统收回。(对象变成僵尸对象。指向此方法的指针值变为0)
(2)当对象被销毁时,系统会自动向对象发送dealloc消息。(对象遗言)
(3)一般要重写dealloc方法。(必须调用super的dealloc)

eg:

- (void)dealloc
{
       [super dealloc];
}


4.概念
(1)野指针:指向僵尸对象(不可用内存)的指针。
注:给野指针发送消息会报错,报错提示:EXC_BAD_ACCESS
(2)僵尸对象:所占用内存已经被回收的对象,僵尸对象不能再使用、
(3)空指针:没有指向任何东西的指针(存储的东西是nil、NULL、0)
注:给空指针发送消息不会报错


5.内存管理原则:
(1)当想使用(占用)某个对象时,就应该让对象的计数器+1 (让对象做一个ratain操作)
eg:

_age = [age ratain];
 

(2)当不想使用(占用)某个对象时,就应该让对象的计数器-1 (让对象做一次release操作) 

eg:

-(void)dealloc
{ 
        [_dog release];//对象计数器-1
        [super dealloc];
}


(3)谁retain,谁release;谁alloc,谁release。
注:对象在set方法中赋值时,应该进行一次retain操作。(基本数据类型不需要管理内存 )


6.set方法内存管理
(1)只要调用了alloc,则必须要有release(或autorelease);
如果对象不是通过alloc产生,则不需要release。

(2)set方法代码规范
1)基本数据类型:直接赋值(基本数据类型不需要进行内存管理)

eg:

- (void)setAge:(int)age
{
   _age = age; 
}


2)OC对象类型

eg:

- (void)setCar:(Car *)car
{
   if ( car != _car) // 1.先判断是不是新传进来的对象
   {
      [_car release]; // 2.对旧对象做一次release
      _car = [car retain]; //  3.对新对象做一次retain
   }                             
}

(3)dealloc代码规范
1>一定要有[super dealloc],而且要放到最后。
2>对self(当前)所拥有的其他对象做一次release

eg:

- (void)dealloc
{
    [_car release]; // 一旦Person release,则车也应该release
    [super dealloc]; // 这段一定要放最后
}

7.@property 内存管理
@property (参数) 对象
eg :
@property (nonatomic,retain) Car *car;

(1)set方法内存管理的相关参数
retain:生成的setter方法中会release旧值,retain新值。(适用于OC对象类型)
assin:直接赋值(默认,适用于非OC对象类型)
copy: release旧值,copy新值。

(2)是否要生成set方法
readwrite:可读写,同时生成setter和getter的声明、实现(默认)
readonly:只读,只会生成getter的声明、实现。

(3)多线程管理(多个线程同时调用某个方法)
nonatomic:代表方法不要考虑线程安全性问题,告诉系统不在set方法中生成多线程代码。(高性能,禁止多线程,推荐使用)
atomic:代表给方法进行加锁,保证线程安全(默认,低性能)
线程保护机制:防止方法在未写入完成时,被其它线程调用,造成数据错误。


(4)setter和getter方法的名称
setter:setter = 方法名,决定了set方法的名称,方法名一定有冒号:
getter:决定了get方法的名称。(一般用在BOOL类型)

8.循环retain和@class
1>(1)@class使用方法:
作用: @class Card 仅仅告诉编译器,Card只是一个类
使用场合:用于.h声明此类,但是不会引入此类的方法和成员变量。
注意点:仅仅声明这个类,不会将此类的方法和成员变量导入,如果需要,则应该在.m文件中#import此类。

(2)引用一个类的规范
1>在.h头文件中用@class来声明类
2>在.m源文件中用#import来包含类的所有东西


(3)@class优点
1>解决循环包含的问题。- >只在.m 源文件中进行引用(可以循环声明,A中声明B,B中声明A)
2>提高了性能。->如果被引入类的头文件进行了修改,不需要全部进行重新编译。


(4)@class 和 #import 区别
1> #import方式会包含被引用类的所有信息,包括被引用类的变量和方法;(使用类所有信息,包括成员变量和方法)

@class方式只是告诉编译器在A.h文件中 ,声明某个类,不知道此类的所有具体信息。(仅仅声明有这个类)

2>如果有上百个头文件都#import了同一个文件,那么一旦被导入文件的头文件稍有改动,后面引用到这个 

文件的所有类的头文件都需要重新拷贝,效率较低。(A->B,B->C,C->D.....一旦A变动,则后面都需要重新编译。程序只编译.h文件)
使用@class方式就不会出现这种问题了,只需在源文件中修改类即可,提高了效率。
(解决了循环包含问题)
3>在.m实现文件中,如果需要引用到被引用类的成员变量或方法时,还需要使用#import方式引入被引用类。

2> 两端循环引用解决方法(循环retain)

一端用retain,一端用assign。、
eg: Car 端 : @property (nonatomic,retain) Person *person;
Person端:@propertor (nonatomic,assign) Car *car


9. autorelease
eg: Person *p = [[[Person alloc] init] autorelease]; //必须存在释放池,才能写autorelease
作用:1>autorelease会将对象放到一个自动释放池中,当自动释放池被销毁时,会对池子里所有对象做一次release。
2>返回对象本身,且不影响对象计数器。
注:池子被销毁时,对象不一定会被销毁,只是做一次release。释放池内可嵌套释放池

eg:

int main()
{
    @autoreleasepool
    { // { 代表开始创建释放池

    } // } 代表销毁释放

}

优点:1>不用在关心对象释放的时间.
2>不需要关心什么使用调用release。
缺点:不能精确控制对象销毁时间。
使用注意:1>占用内存较大的对象不要随便使用autorelease(不能精确控制对象销毁时间)
2>占用内存较小的对象使用,则不会有太大影响。
建议:尽量使用release,因为可以精确控制对象销毁。
使用规范:1>系统自带的方法中,如果不包含alloc、new、copy,那么这些方法返回的对象都是已经autorelease的
2>开发中经常写一些类方法快速创建一个autorelease的对象。(不使用类名,使用self)

eg:

+ (id)Person  
{  
    return [[[self alloc] init] autorelease];  
}  

 


(二)自动管理内存

自动回收内存机制。
优点:不需要人为添加内存管理代码,提高了编程效率与安全性。
1.概念:编译器会自动在适当的地方插入适当的retain、release、autorelease语句。(属于编译器特性)

2.ARC的判断标准:
只要没有强指针指向对象,就会释放对象。
eg: Person *p = [[Person alloc] init];
p = nil;
代码解析:默认情况下,p是强指针。当p等于空时,就没有强指针指向Person对象,这时候编译器会自动将Person对象销毁。

(1)强指针:默认情况下,指针都是强指针(__strong)
(2)弱指针: __weak 修饰
eg: __weak Person *p2 = p ; (p2就是个弱指针)

3. ARC特点:
(1)不允许手工调用release、retain、autoretain。
(2)允许重写dealloc,但是不允许调用[super dealloc];
(3)@property参数
strong:成员变量是强指针,相当于以前retain(使用OC对象)
weak:成员变量是弱指针,相当于以前assign(使用OC对象)
assign:基本数据类型,直接赋值。(使用非OC对象)
(4)以前的retain,全部改为strong,其余不变
eg: @property (nonatomic,retain) Car *car;

改为:@property (nonatomic,strong) Car *car;

4.某.m文件不需要ARC方法
不需要ARC: 添加-fno-objc-arc

      
   需要ARC:-f-objc-arc

5.解决循环引用问题
1>ARC

一端用strong,一端用weak
eg: 
Dog 端 : @property (nonatomic,strong) Person *person;
Person端:@propertor (nonatomic,weak) Dog *car

  


2>非ARC
一端用retain,一端用assign
eg: Dog 端 : @property (nonatomic,retain) Person *person;
Person端:@propertor (nonatomic,assign) Dog *car

6.总结
ARC最大的优点就是极大的提高了程序编写效率,开发者不需要关心对象的销毁时间,不需要担心程序的内存泄漏问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值