当前位置:   article > 正文

iOS ------ MRC

iOS ------ MRC

一,MRC

  1. MRC:Manual reference Counting与ARC是两种不同的内存管理机制。ARC是自动引用计数,有编译器在编译时自动插入内存管理代码。而MRC是手动引用计数,开发者需要手动管理对象的引用计数。
  2. 开发者需要手动调用retain,release,autorelease等方法来增加或减少对象的引用计数,当对象的引用计数为0时,对象的内存将被释放。
  3. 设置MRC:将自动引用计数关掉后就为MRC
//new方式和alloc init方式一样,只不过我们习惯了分两步走。
//MJPerson *person = [MJPerson new];
MJPerson *person = [[MJPerson alloc] init]; //1
//中间写我们想要的代码
[person release]; // 0

或者:
@autoreleasepool {
MJPerson *person = [[[MJPerson alloc] init] autorelease]; //1
//中间写我们想要的代码
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

二,MRC的setter方法

MJPerson里面拥有MJDog,在MJPerson里面重写setDog方法。

- (void)setDog:(MJDog *)dog
{
    if (_dog != dog) {
        [_dog release]; 
        _dog = [dog retain];
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

1,为什么要释放旧值?
如果将新值直接赋给实例变量,而没有堆旧值进行适当的释放操作,旧值的引用计数就从不会减少,对象的内存也不会释放,这就会导致内存泄漏。

2,为什么要retain新值?
当一个对象被复制给一个实例变量,为了确保对象在使用时保持有效,需要增加对象的引用计,这样可以保证在其他地方意外释放对象

3,为什么要检查对象是否相等?
如果_dog和传入的dog是同一个对象,旧值release后引用计数就为0,旧值就会被释放,这时再retain新值就报错。

如果时基本数据类型,就不用进行内存管理,如果是OC对象,setter方法就要这样写。

MRC下的@property只会生成setter和getter方法的声明,如果想生成_age成员变量和setter、getter方法的实现还要使用@synthesize关键字

三,野指针和空指针

1,空指针

  • 指的是没有指向存储空间的指针,(里面存的是nil)
  • 给空指针发消息是没有任何反应
        NSObject *a = [[NSObject alloc] init];   //执行完引用计数为1
        [a release];   //执行完引用计数为 0,实例对象被释放。
        a = nil;   //此时,a变为了空指针。
        [a release];   // 再给空指针a发送消息就不会报错了。
        [a release];
  • 1
  • 2
  • 3
  • 4
  • 5

2,野指针

  • 只要一个对象被释放,我们就称这个对象为僵尸对象(不能再使用的对象)
  • 当一个指针指向一个僵尸对象,我们就称这个指针为也指针
  • 只要给也指针发送消息就会报错
        NSObject *b = [[NSObject alloc] init];   //执行完引用计数为1
        [b release];   //执行完引用计数为 0,实例对象被释放。
        [b release];   // 此时,a 就变成了野指针,再给野指针 a 发送消息就会报错
  • 1
  • 2
  • 3

四,关键字的使用

下面话就看看使用不同的关键字修饰@property并且使用@synthesize关键字,生成setter和getter方法实现有什么不同

1,assign修饰

使用assign生成的setter方法没有内存管理相关的东西,所以assign一般用来修饰基本数据类型,默认情况下就是assign

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

- (int)age
{
    return _age;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2,使用retain修饰

使用retain修饰,生成的setter方法有内存管理相关的东西,所以retain一般用来修饰对象类型。

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

- (MJDog *)dog
{
    return _dog;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

五,自动生成释放池(AutoreleasePool

autorelease是一种支持引用计数的内存管理方式,只要给对象发送autorelease消息,会将对象放在一个自动释放池(AutoreleasePool)中,当自动释放池被销毁时,会对池子里的所有对象做一次release操作。其本质就是对对象的release的调用延迟,延长对象的生命周期

这里只是发送release消息,如果当时的引用计数依旧不为0,则对象依然不会被释放,autorelease方法返回对象本身,且调用完autorelease方法后,对象的计数器不变。

autorelease的使用方法

  • 使用NSAutoreleasePool创建
NSAutoreleasePool* autoreleasePool = [[NSAutoreleasePool alloc] init];//创建自动释放池
Person* p = [[[Person alloc] init] autorelease];//方法释放池
[autoreleasePool drain];//销毁自动释放池
  • 1
  • 2
  • 3
  • 使用@autoreleasePool创建
@autoreleasepool
{ // 创建一个自动释放池
        Person *p = [[Person new] autorelease];
        // 将代码写到这里就放入了自动释放池
} // 销毁自动释放池(会给池子中所有对象发送一条 release 消息)
  • 1
  • 2
  • 3
  • 4
  • 5

六,MRC的优点

  • 精准控制内存管理:MRC允许开发者手动管理对象的引用计数,可以精准地控制对象的生命周期
  • 兼用型好:MRC在iOS早期使用较多,许多老的代码仍然使用MRC进行内存管理

在使用ARC时,开发者只需要关注对象的强引用和弱引用,无需关心对象的引用计数。而在使用MRC时,开发者需要手动管理对象的引用计数,需要仔细地在合适的地方调用retainreleaseautorelease等方法,以避免内存泄漏和野指针问题。

总体而言,ARC是iOS开发中推荐使用的内存管理机制。它可以帮助开发者更专注于业务逻辑的实现,减少了大量的内存管理代码,提高了代码的可读性和可维护性。同时,ARC在性能上也不会比MRC有明显的劣势,因为编译器会在编译时进行优化,生成高效的内存管理代码。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/570965
推荐阅读
相关标签
  

闽ICP备14008679号