iOS开发中atomic属性的子属性消失问题技术问询
嘿,我来帮你捋捋这个页面返回后子属性消失的问题,大概率是这几个坑导致的,你可以一步步排查:
可能的原因及排查方向
readonly属性的实例复用问题
你给ModelObject的lotsOfProps声明的是readonly,那这个属性是不是只在ModelObject初始化时赋值过一次?如果返回页面时,你用的是全新的ModelObject实例,而且这个新实例的lotsOfProps内部子属性没被正确赋值,自然就会出现子属性消失的情况。比如你每次进入页面都重新创建ModelObject,但没把之前的子属性数据传进去。排查方法:在
ModelObject的init方法和你获取实例的代码里加日志,看看返回页面时拿到的是不是同一个实例,以及lotsOfProps的子属性有没有被正确初始化。多线程下的属性访问冲突
lotsOfProps是atomic的,但它内部的prop和myProp是nonatomic的。atomic只能保证lotsOfProps这个对象本身的读写原子性,管不了它内部的属性。如果页面离开时,某个后台线程在异步修改这些子属性(比如不小心置为nil),返回时主线程读到的就是空值。排查方法:给
LotsOfProps的prop和myProp的setter加日志,看看这些属性什么时候被置空,有没有后台线程在操作它们,尤其是页面生命周期回调(比如viewWillDisappear)里的异步任务。页面生命周期中的意外清理
会不会在页面的dealloc或者其他清理方法里,不小心把LotsOfProps的子属性置为nil了?比如你在页面消失时写了清理代码,顺手把这些子属性清空了,但返回时没重新赋值。排查方法:搜索项目中所有修改
prop和myProp的代码,重点看页面销毁、消失相关的方法,有没有误操作的置空逻辑。对象持有关系的隐性问题
虽然你声明prop和myProp是strong,但有没有可能代码里不小心写成weak了?或者这些子属性指向的对象被其他地方提前释放了?不过这个概率相对小,但也可以检查一下属性声明的正确性。
建议的解决方案
确保ModelObject实例的复用
导航时传递ModelObject实例时,尽量复用同一个对象,比如把它存在父控制器、ViewModel单例或者全局容器里,不要每次进入页面都新初始化一个。这样返回时就能直接拿到之前带有完整子属性的实例。给子属性加线程安全保护
如果确实存在多线程操作的情况,可以给LotsOfProps的子属性加锁,或者改成atomic(注意atomic会有轻微性能损耗,按需选择)。比如用@synchronized包裹读写逻辑:@implementation LotsOfProps - (void)setProp:(AProp *)prop { @synchronized(self) { _prop = prop; } } - (AProp *)prop { @synchronized(self) { return _prop; } } // myProp同理 @end清理页面生命周期的误操作代码
彻底排查所有修改prop和myProp的地方,删掉页面消失时不必要的置空逻辑。如果确实需要清理,要区分首次离开和再次返回的场景,保留需要复用的数据。优化readonly属性的内部更新逻辑
虽然lotsOfProps对外是readonly,但可以在ModelObject内部开放私有接口来更新子属性,避免外部误修改的同时,保证内部能安全更新数据:@interface ModelObject () @property (atomic, strong, readwrite) LotsOfProps *lotsOfProps; @end @implementation ModelObject // 内部更新子属性的方法 - (void)updateLotsOfPropsWithProp:(AProp *)prop myProp:(MyProp *)myProp { self.lotsOfProps.prop = prop; self.lotsOfProps.myProp = myProp; } @end
内容的提问来源于stack exchange,提问作者MichaelGofron

