Objective-C中Setter与属性访问:Block警告下该用self.属性还是直接变量?
嘿,这个问题我之前在项目里也纠结过,尤其是Xcode弹出那个“Block implicitly retains 'self'”警告的时候,其实背后是ARC内存管理和代码规范的双重考量,我给你捋捋最佳实践:
核心结论:在Block中必须显式使用
self.collectionView这类属性访问方式 为什么不能直接访问后台变量(ivar)?
- 内存管理隐患:直接写
_collectionView时,Block会隐式捕获self(因为ivar属于self),但你看不到self的存在,很容易忽略循环引用的风险——比如如果Block被self持有的对象(比如一个属性)保留,就会形成self -> 持有Block的对象 -> Block -> self的循环,导致内存泄漏。Xcode的警告就是在提醒你这个隐式捕获的问题,要求你显式写self来明确意图。 - 破坏封装与逻辑一致性:属性的getter/setter往往带有额外逻辑,比如KVO通知、懒加载、线程安全校验、
didSet/willSet里的业务处理。直接访问ivar会跳过这些逻辑,导致状态不一致——比如你直接给_collectionView赋值,就不会触发didSet里的刷新UI代码,界面可能不会更新。
那怎么解决循环引用的问题?
既然要显式用self.property,就得配合弱引用避免循环,这是标准操作:
Objective-C示例:
__weak typeof(self) weakSelf = self; [self.someAsyncOperation addCompletionBlock:^{ // 强引用weakSelf,保证Block执行期间self不会被释放 __strong typeof(weakSelf) strongSelf = weakSelf; if (strongSelf) { [strongSelf.collectionView reloadData]; } }];
Swift示例:
someAsyncOperation.addCompletionHandler { [weak self] in guard let strongSelf = self else { return } strongSelf.collectionView.reloadData() }
这么做的好处:弱引用打破循环,强引用保证Block执行时self的稳定性,判空避免野指针崩溃。
那Setter方法里的旧习惯要不要改?
关于Setter里直接访问ivar的老做法,其实现在依然可以用,但要分场景:
- 如果是手动实现的Setter(比如Objective-C里手动写
-setCollectionView:),直接访问ivar是安全且必要的——因为如果在Setter里写self.collectionView = newValue会触发递归调用,导致死循环。 - 如果是自动生成的Setter(比如Objective-C的
@synthesize、Swift的默认属性),或者你依赖属性的didSet/willSet逻辑,那尽量用self.property访问,避免跳过这些逻辑。
最后再划个重点
- Block里:永远显式用
self.property,别碰ivar,同时配合弱/强引用处理内存问题。 - Setter里:手动实现时用ivar,自动生成时优先用属性访问。
- 代码可读性也是关键:显式写
self能让其他开发者一眼看出Block持有了self,减少维护时的坑。
内容的提问来源于stack exchange,提问作者Ricky
相关产品推荐
相关产品推荐

