备案的时候需要网站吗,晚上必看的正能量网站,德宏芒市建设局网站,福建建设工程设计备案网站如果对象A持有对象B#xff0c;B作为A的associated object#xff0c;并且表面上B没有其他被强引用的地方#xff0c;那么对象A被释放时#xff0c;对象B一定会同时释放吗#xff1f;大部分情况下是#xff0c;但真有不是的时候。最近实现代码的时候不小心就碰到了这样的…如果对象A持有对象BB作为A的associated object并且表面上B没有其他被强引用的地方那么对象A被释放时对象B一定会同时释放吗大部分情况下是但真有不是的时候。最近实现代码的时候不小心就碰到了这样的特殊情况。
需求
需要监听对象A释放dealloc并执行对象A的a方法。此时引入对象B并作为对象A的associated object。A释放时触发B释放在B的dealloc方法中执行A的a方法。对象B需要一个指向对象A的属性并声明为unsafe_unretained或assign因为weak指针此时已经失效了。
示例代码
interface MyObject1 : NSObject
endimplementation MyObject1
- (void)foo {NSLog(success);
}
endinterface MyObject2 : NSObject
property (nonatomic, unsafe_unretained) MyObject1 *obj1;
endimplementation MyObject2
- (void)dealloc {[self.obj1 foo];
}(instancetype)create {return [[self class] new];
}
endimplementation ViewController(void)load {[self fun1];
}(void)fun1 {MyObject1 *mo1 [MyObject1 new];synchronized (self) {MyObject2 *mo2 [MyObject2 create];mo2.obj1 mo1;objc_setAssociatedObject(mo1, selector(viewDidLoad), mo2, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}
}
end
问题
运行时出现崩溃unsafe_unretained指针已经野了和预期的不一样。堆栈是这样的 观察崩溃的堆栈发现mo2对象是被自动释放池释放了。因为mo1对象是在函数退出时就立即释放这样导致mo1比mo2先被销毁mo2访问了无效指针导致了崩溃。
这个问题和synchronized有关系但目前我还不知道它和arc之间有什么联系。下面给出另一个case修改一行代码就不会崩溃了 (void)fun2 {MyObject1 *mo1 [MyObject1 new];MyObject2 *mo2 [MyObject2 create];synchronized (self) {mo2.obj1 mo1;objc_setAssociatedObject(mo1, selector(viewDidLoad), mo2, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}
}
实际上只是把mo2的声明移动到了synchronized外面堆栈变成了这样 这时mo2的释放发生在调用方法的结束时。
分析
使用Hooper查看汇编代码观察fun1和fun2的不同。节选出关键部分 核心在于fun1中创建mo2后调用了retainfun2中调用的则是objc_retainAutoreleasedReturnValue。
我们再来看看create方法
关键的一行在最后调用了objc_autoreleaseReturnValue。
关于objc_retainAutoreleasedReturnValue和objc_autoreleaseReturnValue请移步 https://www.jianshu.com/p/2f05060fa377 。大意是这两个方法成对出现时可以优化掉[[obj autorelease] retain]这种骚操作。
结论
在fun1中由于没有objc_retainAutoreleasedReturnValue取而代之的是retain导致对象被放入自动释放池。对于synchronized为什么会造成不同我还没有那么深入。
因为全局自动释放池会延迟对象的释放如果代码非常依赖对象的释放时机则会比较危险。我认为这样做是最保险的创建一个局部自动释放池保证局部变量在函数结束时立即释放 (void)fun3 {MyObject1 *mo1 [MyObject1 new];autoreleasepool {synchronized (self) {MyObject2 *mo2 [MyObject2 create];mo2.obj1 mo1;objc_setAssociatedObject(mo1, selector(viewDidLoad), mo2, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}}
}
原文链接 本文为云栖社区原创内容未经允许不得转载。