以下Objective-C代码是否会产生强引用循环?回调引用self存疑
你的代码会不会产生强引用循环?
答案是:不会形成永久的强引用循环,但直接在block里用self还是有潜在问题,咱们来一步步拆解:
为什么不会形成循环引用?
强引用循环的核心是「两个或多个对象互相持有强引用,形成ARC无法自动释放的引用环」。咱们梳理下当前的引用关系:
UIImagePickerController(代码里的picker)会强引用传入的completionblock;- 你的
completionblock里直接写了self,所以block会强引用当前的视图控制器; - 关键是:
self并没有强引用这个picker——picker是方法参数,你没在self里用强引用属性持有它,而且UIKit内部的presentingViewController是弱引用(专门用来避免循环)。
当dismiss动画完成后,UIKit会释放picker,picker随之释放它持有的block,block也会释放对self的强引用,整个引用链直接断开,ARC能正常回收这些对象,不会形成永久循环。
那直接用self有什么问题?
虽然不会触发循环引用,但直接强引用self可能带来两个麻烦:
- 延长
self的生命周期:如果用户已经把当前页面pop掉,self本来该被释放,但因为block持有强引用,self会被保留到block执行完毕,造成不必要的资源浪费; - 潜在逻辑错误:如果
self的状态(比如profileViewModel)在block执行前已经失效,继续执行代码可能引发异常或不符合预期的行为。
推荐的正确写法
用「弱引用+强引用」的组合,既从根源避免循环引用,又保证block执行期间self不会被意外释放:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { // 先创建self的弱引用 __weak typeof(self) weakSelf = self; [picker dismissViewControllerAnimated:YES completion:^{ // 在block内部转为强引用,避免self执行过程中被释放 __strong typeof(weakSelf) strongSelf = weakSelf; if (!strongSelf) return; // self已经释放的话直接退出 UIImage *image = [strongSelf cropImageWithInfo:info]; if (currentScreen == CurrentScreenApartment) { [strongSelf.profileViewModel.apartmentPhotos addObject:[RuntimePhoto runtimePhotoWithImage:image]]; } else { // 你的其他逻辑 } }]; }
这种写法的好处:
- 弱引用
weakSelf不会让block持有self的强引用,彻底杜绝循环引用可能; - 内部转强引用
strongSelf,保证代码执行期间self的稳定性,避免野指针; - 先判断
strongSelf是否为空,确保后续代码只在self有效时执行。
内容的提问来源于stack exchange,提问作者AnonProgrammer
相关产品推荐
相关产品推荐

