C++/Objective-C中避免根对象被删除及强引用问题排查
C++/Objective-C混合代码中的引用生命周期问题
原始代码
#import <YandexMobileAds/YandexMobileAds-Swift.h> @class AdHook; namespace MyApp { class AdHolder { public: AdHolder(IosInterstitialAd* cpp_ad); AdHook* m_hook; }; } using namespace MyApp; @interface AdHook : NSObject <YMAInterstitialAdLoaderDelegate, YMAInterstitialAdDelegate> { @public IosInterstitialAd* m_cppAd; @public YMAInterstitialAdLoader* m_loader; @public YMAInterstitialAd* m_interstitialAd; } @end @implementation AdHook - (id)initFromCpp:(IosInterstitialAd *)cpp_ad { if (self = [super init]) { m_cppAd = cpp_ad; m_interstitialAd = nil; m_loader = [[YMAInterstitialAdLoader alloc]init]; m_loader.delegate = self; } return self; } AdHolder::AdHolder(IosInterstitialAd* cpp_ad) { [YMAMobileAds enableLogging]; m_hook = [[AdHook alloc]initFromCpp:cpp_ad]; } void SomeOtherClass::load() { NSLog(@"IosInterstitialAd::load()"); YMAAdRequestConfiguration* configuration = [[YMAAdRequestConfiguration alloc]initWithAdUnitID:@"demo-interstitial-yandex"]; [m_holder->m_hook->m_loader loadAdWithRequestConfiguration:configuration]; }
初始问题
我在C++代码中创建AdHolder类实例,其构造函数会创建Objective-C类AdHook的实例,而AdHook又会创建内部Objective-C对象。但我不清楚m_hook的生命周期,怀疑它会被提前销毁,因为在YMAInterstitialAdLoaderDelegate回调中访问m_hook->m_interstitialAd时出现错误值导致应用崩溃。
请问m_hook是否为强引用?若不是该如何将其设为强引用?
编辑1
我尝试在应用中给多个对象添加retain调用,最终通过给AdHook::m_interstitialAd添加retain调用解决了崩溃问题:
- (void)interstitialAdLoader:(YMAInterstitialAdLoader * _Nonnull)adLoader didLoad:(YMAInterstitialAd * _Nonnull)interstitialAd { NSLog(@"IosInterstitialAd::YMAInterstitialAdLoader::didLoad, %@", interstitialAd); m_interstitialAd = [interstitialAd retain]; m_interstitialAd.delegate = self; }
应用访问m_interstitialAd时不再崩溃。现在问题变为:AdHook::m_interstitialAd是否为强引用?
回答
关于m_hook的引用类型
AdHolder中的m_hook是普通C指针,不是强引用。Objective-C的ARC仅管控Objective-C对象的引用关系,C指针不在ARC的管理范围内:
- 你在构造函数中用
alloc创建的AdHook实例初始引用计数为1,但因为m_hook是C++指针,ARC不会将其视为强引用持有。一旦没有其他Objective-C强引用指向该实例,ARC会自动释放它,导致后续回调中访问m_hook时出现野指针崩溃。
将m_hook设为强引用的两种方法:
- ARC环境下:把
m_hook声明为__strong AdHook* m_hook;,让ARC自动维护引用计数,保证对象在被持有期间不会被释放。 - 手动引用计数(MRC)环境下:在
AdHolder构造函数中创建实例后调用[m_hook retain],在AdHolder的析构函数中调用[m_hook release],手动控制引用计数。
关于AdHook::m_interstitialAd的引用类型
你添加retain后崩溃解决,说明原本的m_interstitialAd不是强引用:
- 如果是MRC环境,直接赋值
m_interstitialAd = interstitialAd只是指针赋值,不会增加引用计数。当YMAInterstitialAdLoader释放广告对象后,m_interstitialAd就会变成野指针,调用retain手动增加引用计数后,对象会被你持有直到你调用release,因此不再崩溃。 - 如果是ARC环境,实例变量默认是强引用,但可能存在其他逻辑导致
m_interstitialAd被提前释放(比如被弱引用覆盖或其他地方的释放操作)。你可以显式声明为__strong YMAInterstitialAd* m_interstitialAd;来明确强引用,避免混淆。
内容的提问来源于stack exchange,提问作者Dmitriano
相关产品推荐
相关产品推荐

