这个问题比较简单,我想很多朋友都知道的一清二楚,当然也会有很多朋友只知道一点点(以初学者为主)。当初学iOS的时候全篇点语法,后来看到说点语法要经过方法派发,比较慢,直接访问实例变量比较快,于是又全篇直接访问,再后来看到有人说过,写入实例变量的时候用点语法,读取实例变量的时候直接访问就行。当初知识面比较窄,想着记住就OK。今天把这个问题翻出来验证一番,也为以后学习iOS的朋友提供个方便。
先放结论
这个结论正着好像不太好说,所以反过来说说直接访问实例变量和使用点语法会带来的一些相应问题⊙﹏⊙
1、直接访问无法触发KVO
2、直接访问会绕过属性的某些某些某些(重三遍)权限修饰符(如copy)
3、在访问器方法中使用点语法会导致递归
4、读取变量值的时候一般可以直接访问
5、貌似没有了,等朋友们补充~
开始验证(xue xi)
针对上面的几点,本文主要验证绕过某些属性的权限修饰符这一点,其他的几点比较容易理解,在这里就不验证了。代码比较简单,不打算贴了,直接说说都有啥。首先有一个person类、一个dog类,person有两个属性:name(copy),dog(strong)。项目对main.m禁用arc方便打印retainCount,对两个类要开启arc。
main.m如下
很简单的代码,有一个位置可能会有朋友有疑问,为什么name那要用mutableString,这个在这里就不过多解释了,总之用mutable才能有效果,详细的大家可以去看另一篇博客,比我写的这些简单东西有意思多了%>_<%
给链接:ARC & MRC下string内存管理策略探究
然后我们先看看一般情况下我们使用点语法设置属性值的情况
这里简单地把name的地址打出来了,方便大家理解。可以看到dog的retainCount是2,因为它是strong的,main中retain一次,person中又retain一次。再看name,属性的地址和main中变量的地址不一样,很简单,因为它是copy的,所以retainCount = 1 。
接下来才是我们真正验证的环节,我们来看看不适用点语法而直接访问实例变量会是什么样
dog的retainCount依旧是2,看来直接访问实例变量对dog没有啥影响
再看name,奇怪的是它的retainCount也变成2了,再看地址,发现main中name和person中name的地址居然是一样的,而我们对name属性给的却是copy。可见,使用直接访问实例变量的方式,系统将不执行copy行为,而是变得跟strong是一模一样。对于字符串使用strong修饰会有什么样的危险我想大家都是知道的——容易被篡改。
那么为什么直接访问会绕过copy,而不绕过我们给dog的strong修饰呢?其实呢,它都有绕过的。因为我们使用直接访问实例变量就没有经过属性的访问器,也就把属性的权限修饰符直接晾一边了,并没有使用它。虽然我们没有使用属性,但是系统依旧为我们合成了实例变量,而合成的时候给实例变量的修饰符是根据属性的修饰符来的。但是,属性有的修饰符实例变量不一定有,实例变量可以有strong、weak,但是它不会有copy,因为系统对于实例变量,可以自动为我们retain,但是没法为我们自动执行深拷贝。所以copy在使用直接访问的方式的时候被直接忽略,而strong和weak属性因为实例变量也拥有相应修饰符而不会有任何问题。
再总结
所以,,当我们的属性使用的是strong、weak这些实例变量也能够拥有的修饰符的时候,是可以在设置实例变量的时候也直接访问的,不会有问题,但是当我们使用copy这类实例变量没有拥有的修饰符的时候,直接访问是会出问题的,这时候就必须使用点语法。