You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Objective-C中retainCount返回错误值问题(MRC环境代码示例)

MRC环境下设置代理后retainCount返回值不符合预期的原因与解决

先把你的代码贴出来方便大家对照分析:

@class Person;

@protocol PersonDelegate <NSObject>
- (void)sendLetterForPerson:(Person *)p;
@end

@interface Person : NSObject
@property (nonatomic, weak) id <PersonDelegate> delegate;
- (void)writeLetterComplete;
@end

@interface TestController ()<PersonDelegate>
@property (nonatomic, strong) Person *per;
@end

// 调用代码
_per = [[Person alloc] init];
_per.delegate = self;
NSLog(@"%lu",(unsigned long)_per.retainCount);
NSLog(@"%lu",(unsigned long)_per.delegate.retainCount);

好,咱们来拆解这个问题的核心:

问题根源

  1. MRC不支持weak关键字
    weak是ARC专属的内存管理修饰符,在MRC环境下,编译器要么把weak当作assign处理,要么直接抛出编译警告/错误。你用weak修饰代理,本质上和assign没区别,但这会让你对代理的内存管理逻辑产生误解——你以为weak会自动处理引用计数,但MRC里根本没有这个机制。

  2. retainCount本身就是个不可靠的“坑”
    Apple官方早就明确说过,别依赖retainCount的返回值判断对象引用计数。系统内部会对对象做很多隐式操作:比如autorelease池的临时retain、NSString常量池缓存、调试环境的额外引用等,都会让retainCount的结果和你预期完全不符。比如你的TestController实例(也就是self)因为被视图层级持有,它的retainCount可能远大于你手动操作的数值。

  3. 代理内存管理的认知偏差
    MRC中代理的正确写法是用assign(用retain会导致循环引用),assign不会增加被代理对象的引用计数,所以你打印_per.delegate.retainCount得到的是self的引用计数,但这个值受系统影响极大,完全不能反映你设置代理的操作。

解决方案

  • 把代理的weak改成assign
    这是MRC下代理的标准写法,既避免循环引用,又符合MRC内存管理规则:

    @property (nonatomic, assign) id <PersonDelegate> delegate;
    
  • 放弃用retainCount验证内存管理
    要确认对象是否会被正确释放,重写dealloc方法才是靠谱的方式。比如在Person和TestController中分别添加:

    // Person.m
    - (void)dealloc {
        NSLog(@"Person被释放了");
        [super dealloc]; // MRC下必须调用super的dealloc
    }
    
    // TestController.m
    - (void)dealloc {
        NSLog(@"TestController被释放了");
        [_per release]; // MRC下手动释放strong属性的对象
        [super dealloc];
    }
    

    运行后观察控制台的释放日志,这才是判断内存管理是否正确的标准。

  • 确保MRC环境配置正确
    检查target的Build Settings,把Objective-C Automatic Reference Counting设置为NO,避免ARC和MRC混合导致的奇怪问题。

内容的提问来源于stack exchange,提问作者user9067376

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:36:59