iOS内存管理之引用计数

随笔6个月前发布 一颗糖
79 0 0

MRC现在很少用了, 但原理依旧在那里, ARC环境下, 不需要手动retain, release了, 但其实只是编译器帮你做了这些事情.

那么iOS引用计数究竟是怎么回事了, 我们先从assign关键字说起

现在提到assign关键字, 一般用来修饰非OC对象, 比如一些基本数据类型, 比如NSInteger, BOOL, 以及C语言的基本数据类型, int, double之类的, 因为assign关键字只是分配一块内存空间, 并没有做任何关于引用计数的操作.

所以, 在ARC环境下, 有点类似于weak关键字, 但跟weak关键字修饰的属性的区别是, weak关键字修饰的对象, 会加入弱引用表中, 对象被销毁时, 指向对象的指针也会被置为 nil, 但是assign关键字修饰的对象, 对象被销毁时, 指向对象的内存并不会置为nil, 这时候在去访问那片内存空间, 是非常危险的, 会产生EXEC_BAD_ACCESS

iOS内存管理之引用计数

比如在上面图示的例子中, 先跳转到一个新的控制器, 然后返回控制器的时候, 控制器会被销毁, 这时候, 再去访问用assign关键字修饰的控制器对象, 就会报EXEC_BAD_ACCESS.

所以, 在ARC环境下, 是不能用assign去修饰OC对象的.

那么在MRC环境下呢? 在MRC环境下, 默认就是assign, 但是, 用assign修饰也是会有问题的.

iOS内存管理之引用计数

比如在上面的代码中, p1.aCat 指向的那片内存空间已经被提前release了, 后面仍然去访问, 那就会出现EXEC_BAD_ACCESS.

但如果此时用retain修饰就不会有问题:

iOS内存管理之引用计数

这是因为, p1.aCat = cat实际上给p1发送setACat消息:

- (void)setACat:(Cat *)aCat {
    if (_aCat != aCat) {
        [_aCat release];
        _aCat = aCat;
        [aCat retain];
    }
}

本质上就是这样的, 先判断旧的对象和新赋值的对象是不是同一个对象, 如果是, 就什么都不做, 如果不一样, 就先给旧对象发送release消息, 然后赋值操作, 最后, 将新对象的引用计数+1, 这就是retain关键字做的事情, 所以如果重复赋值, 引用计数也不会变化

MRC环境下, 使用retain关键字, 除了在set方法引用计数+1, 在get方法中, 并不会对对象引用计数+1

iOS内存管理之引用计数

如上图所示, 在MRC环境下, 引用计数为2

但是在ARC环境下, 使用retain关键字, 除了在set方法引用计数+1, 在get方法中, 也会对对象引用计数+1

iOS内存管理之引用计数

事实上在ARC环境下使用retainstrong的效果是一样的:

iOS内存管理之引用计数

也可以参考这张图:
ARC环境下使用以下关键字的效果:

iOS内存管理之引用计数

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...