黑马程序员-[OC语言] 第三篇:MRC手动内存管理总结

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

OC加强--第一天学习总结:

1. 内存管理范围:
 1)管理任何继承NSObject 的对象,对其他的基本数据类型无效。


2. OC内存管理的原理
1)引用计数器的作用:引用计数器是判断对象要不要回收的依据(存在一种例外:对象值为nil 时,引用计数器为0 不回收空间)就是计数器是否为0,若为0 则不存在。
2)引用计数器的操作;
给对象发送消息,进行相应的计数器操作;
retain 消息:使计数器加1.
release消息:使计数器减1;
retainCount : 得到引用计数器的值;
3) 如果一个对象被释放的时候,会有“临终遗言”(会调用该对象的dealloc 方法);
注意:(1)dealloc 方法是NSObject的,一般我们需要重写dealloc方法。
(2)在dealloc方法内部,要调用[super dealloc];


3.内存管理的分类:
1)MRC 手动内存管理;
2)ARM 自动内存管理;
3)垃圾回收,OC一般不使用;


4.内存管理研究的内容;
1) 野指针:

(1) 定义的指针没有初始化。

(2)指向的空间已经被释放了。
2) 内存泄漏;

Person *P =[Person new];如果栈区的P已经被释放了,而堆区的空间还没释放,此时会造成内存泄漏;


5.单个对象内存管理野指针问题:
1)  如果内存对象已经被释放掉了,就不能在使用了。
2)给nil 发送任何消息,都没有效果,所以nil调用任何方法,都不会有结果;
3)  避免使用僵尸对象方法是,对象释放后,给对象付值为nil;


6. 单个对象内存泄漏问题:
1)对象创建完成,使用之后,没有释放内存;此时会泄漏内存;
2)不遵守内存管理规则,多次申请而不释放(或者少释放);
3) 不当的使用new,或者中间使用了nil给对象复制.
4)  在方法中,对会传入的对象进行了retain   然后只进行了一次释放;


7.  多个对象内存管理:
1)注意野指针的访问:一个对象在没有销毁之前,可以任意多次的调用自己的方法,如果因为里面可能调用了已经销毁的对象了,但是此时会报错(一定要开启僵尸对象检测模式)。
2)一定要注意, 当一个对象作为另一个对象的实例变量的时候,注意变量一定要销毁,销毁的方法有,在set方法中,如果调用的还是同一个方法,则加上一个[P retain]否则,如果不是同一个方法,则要先加上一个dealloc 然后再[P retain];
3) 如果在一个类中,有其他的对象(关联关系),则在写set方法书写的时候,要先release 旧值,然后retain新值。


8. set方法的内存管理原则:
1)基本数据类型的数据作为实例变量,set方法直接赋值既可。
2)如果在一个类中有其他类的对象(关联关系)则在set方法书写的过程中,要先判断是否是头一个对象,如果不是,应该先释放旧值(release 旧值),然后再retain 新值。如果是同一个对象,则只需让set方法直接赋值既可。
一般写法为:

-(void)setDog:(Dog *)dog{
    if(_dog !=dog){
     [_dog  release];
    _dog =[dog retain];
    }
}

9.@property参数:
1)格式:@property (参数1,参数2)数据类型  方法名

2)替换set/get方法名称:
格式为:

@property(nonatomic assign  setter =isVip: )bool vip;
@property(nonatomic assign  getter =isVip: )bool vip;

10.@class的使用:

@class  类名XXX: 含义是:告诉编译器,XXX是一个类,至于类有哪些属性和方法,此处不去检测,好处:如果XXX 文件内容发生了改变,而不需要重新编译。如果要引用另一个文件中的实例变量,进行相应的操作,则需要在.m头文件中引用(#import  类名)。
#import与@class的区别
1.import会包含这个类的所有信息,包括实体变量和方法,而@class只是告诉编译器,其后面声明的名称是类的名称,至于这些类是如何定义的,暂时不用考虑,后面会再告诉你。
2.在头文件中, 一般只需要知道被引用的类的名称就可以了。 不需要知道其内部的实体变量和方法,所以在头文件中一般使用@class来声明这个名称是类的名称。 而在实现类里面,因为会用到这个引用类的内部的实体变量和方法,所以需要使用#import来包含这个被引用类的头文件。
3.在编译效率方面考虑,如果你有100个头文件都#import了同一个头文件,或者这些文件是依次引用的,如A–>B, B–>C, C–>D这样的引用关系。当最开始的那个头文件有变化的话,后面所有引用它的类都需要重新编译,如果你的类有很多的话,这将耗费大量的时间。而是用@class则不会。
4.如果有循环依赖关系,如:A–>B, B–>A这样的相互依赖关系,如果使用#import来相互包含,那么就会出现编译错误,如果使用@class在两个类的头文件中相互声明,则不会有编译错误出现。
所以,一般来说,@class是放在interface中的,只是为了在interface中引用这个类,把这个类作为一个类型来用的。 在实现这个接口的实现类中,如果需要引用这个类的实体变量或者方法之类的,还是需要import在@class中声明的类进来.


11.循环retain问题:会导致两个对象都会内存泄漏;
防止方法:
1)让某个对象多释放一次(要注意释放顺序)2)一端使用assign    一段使用retain(推荐使用)
12.NSString类的内存管理:
1)字符串的常量池:如果需要的字符串在常量池中已经存在,则不会再次分配空间。
13.autorelease的基本使用:
1)自动释放池是一种特殊的栈结构,对象可以加入到自动释放池中,自动释放池结束的时候,会给池中的对象发送一条release消息。
2)加入自动释放池,格式:[对象  autorelease];
3)加入到自动释放池中以后,引用计数不会改变;
4)@autoreleasepool{自动释放池开始   }自动释放池结束;
5)当一个对象调用autorelease时,会将这个对象放到位于栈顶的释放池中。

实例如下:

#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
    //1 创建自动释放池
    Person *p = [Person new];  // p  1
    @autoreleasepool {//自动释放池开始
        
        [p run];
 
        NSLog(@"%lu",p.retainCount); // 1
        
        // [p autorelease] 把对象p加入到自动释放池中
        // 注意:加入到自动释放池中以后, 引用计数不会变化
        [p autorelease];  //加入自动释放池,
        NSLog(@"%lu",p.retainCount); // 1
        
        [p run];
        
    }//自动释放池结束   [p release];
    [p run];
    return 0;
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值