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环境下使用以下关键字的效果:
