网易面试题引发的思考

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_30746437/article/details/78112634
题目:下面代码会发生什么问题?
@property (nonatomic, strong) NSString *target;
//....
dispatch_queue_t queue = dispatch_queue_create("parallel", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 1000000 ; i++) {
    dispatch_async(queue, ^{
        self.target = [NSString stringWithFormat:@"ksddkjalkjd%d",i];
    });
}
这段代码,看上去没有什么问题,运行一下,发现奔溃,报错EXC_BAD_ACCESS

这样看来是对已经释放的对方再次发送了release消息。
回头看这代码,dispatch_async是异步调用,也就是说在这个循环中,前一个异步调用执行的语句还是没有完成,后一个已经开始在执行了,代码块中的程序执行相互是不受影响的。但是问题在于执行的是同一段代码,我们在来看target是用strong来修饰的,set方式实际执行了什么?
- (void)setTarget:(NSString *)target {
    [target retain];//先保留新值
    [_target release];//再释放旧值
    _target = target;//再进行赋值
}
这样看来,前一个异步调用执行到将要执行第三步,后一个再次开始执行第二步relase,这样新的target还没有被赋值,所以_target本来就处于被释放的状态,再次relase就奔溃了。

通过这个案例我们发现循环的异步调用某一个方法时,需要考虑改方法的实际情况,防止出现EXC_BAD_ACCESS的情况,我们在大多数时候都是直接使用ARC,没有关注到内存释放、对象消亡的过程。一旦出现EXC_BAD_ACCESS,多半都是因为你提前释放了某个对象,然后又在对该对象进行操作。

这样的话,我们提供一种调试方法,来帮助准确定位问题所在,Xcode开启僵尸模式
选中编译项目点击Edit Scheme->选中diahnostics->勾选Zombie Object(僵尸对象选项),如图


这样的话,如果项目中存在僵尸对象,控制台会打印出具体的问题,准确定位到被提前释放的对象。
展开阅读全文

类域引发思考

12-30

这一段时间一直在琢磨对象模型,现在看到个问题都想用模型来解释,不过确实如此,几乎什么都可以用对象模型来解释rn搞这个模型就绝对离不开域rn到底域是什么?这个恐怕不是三言两语说的明白的,每个人都有一定的概念,但是可能大不相同rnC++上指的是作用域rn一对大括号就对应了一个作用域,学过C++的都知道,作用域里的局部变量出了作用域就消亡了(根本原因是栈恢复)rn而对于静态变量,编译器编译的时候做了处理,解析为“全局变量”,但这个全局变量和一般意义上的全局变量不同,它带有记号,这个记号就是 域,标志着这个所谓的全局变量是专属于这个域的rn重点是类域,其实类域和一般域没什么区别也是一对形成的而已rn要讨论的自然是函数和数据rn其实同样是编译器在编译的时候进行了处理,把成员函数(不管是静态还是非静态,虚的还是非虚的)全都解析成了全局函数,但是又带上了记号,那就是专属于某个类的记号,当然解析后的函数全部是独一无二的rn只是寻址这些函数的时候有所区别,这些区别也就是C++本身的特性所导致的,具体什么特性不再此讨论rn然后就是数据成员,静态数据成员,独立于域依附于域。同样编译的时候解析成了专属此类的全局变量,非静态变量是和类的对象同生命的,依附于对象而存在。rn静态成员函数和静态成员数据是独立于域的,所以不需要用对象来存取,依附于域,说明可以用对象来存取,也可以用类名来存取。rn说了这么多,到底域是个什么好像还是很没头绪rn[img=http://hi.csdn.net/attachment/201112/30/10181841_1325218067OLJo.jpg][/img]rn上面这张图上面的虚线就是所谓的类域,局部变量是依附于对象生存在栈空间,静态函数和数据以及非静态函数被解析后分别存在于数据段和代码段rn一些理解,希望对大家有所帮助,有不同意见的请回贴已作深入探讨,谢谢!rnrn 论坛

没有更多推荐了,返回首页