MRC
现在很少用了, 但原理依旧在那里, ARC
环境下, 不需要手动retain
, release
了, 但其实只是编译器帮你做了这些事情.
那么iOS
引用计数究竟是怎么回事了, 我们先从assign
关键字说起
现在提到assign
关键字, 一般用来修饰非OC对象, 比如一些基本数据类型, 比如NSInteger
, BOOL
, 以及C语言的基本数据类型, int
, double
之类的, 因为assign
关键字只是分配一块内存空间, 并没有做任何关于引用计数的操作.
所以, 在ARC
环境下, 有点类似于weak
关键字, 但跟weak
关键字修饰的属性的区别是, weak
关键字修饰的对象, 会加入弱引用表中, 对象被销毁时, 指向对象的指针也会被置为 nil
, 但是assign
关键字修饰的对象, 对象被销毁时, 指向对象的内存并不会置为nil
, 这时候在去访问那片内存空间, 是非常危险的, 会产生EXEC_BAD_ACCESS
比如在上面图示的例子中, 先跳转到一个新的控制器, 然后返回控制器的时候, 控制器会被销毁, 这时候, 再去访问用assign
关键字修饰的控制器对象, 就会报EXEC_BAD_ACCESS
.
所以, 在ARC
环境下, 是不能用assign
去修饰OC
对象的.
那么在MRC
环境下呢? 在MRC
环境下, 默认就是assign
, 但是, 用assign
修饰也是会有问题的.
比如在上面的代码中, p1.aCat
指向的那片内存空间已经被提前release
了, 后面仍然去访问, 那就会出现EXEC_BAD_ACCESS
.
但如果此时用retain
修饰就不会有问题:
这是因为, 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
如上图所示, 在MRC
环境下, 引用计数为2
但是在ARC
环境下, 使用retain
关键字, 除了在set
方法引用计数+1
, 在get
方法中, 也会对对象引用计数+1
事实上在ARC
环境下使用retain
和strong
的效果是一样的:
也可以参考这张图:
在ARC
环境下使用以下关键字的效果: