我有一个包装C ++组件的Objective-C层。当前的设计意味着健壮,这意味着用户可以随时将实例设置为nil(ARC),并且底层组件将正确地和同步地清理自己。
我遇到的问题是顶部的Obj-C实例将自身传递给底层C ++层,作为在操作期间访问的__weak引用(例如调用委托,更改某些状态等)以及当用户释放通过将Obj-C实例设置为nil,在尝试从dealloc内部访问它时会发生EXC_BAD_ACCESS。
以下是一些示例代码,仅用于演示有问题的场景。
Wrapper.h
#import <Foundation/Foundation.h>
#import "Underlying.h"
@interface Wrapper : NSObject {
Underlying* _cppUnderlying;
}
- (instancetype)init;
- (void)dealloc;
@end
包装+ Private.h
#import "Wrapper.h"
@interface Wrapper () {
@package
NSMutableDictionary* _dict;
}
@end
Wrapper.mm
#import "Wrapper+Private.h"
@implementation Wrapper
- (instancetype)init
{
self = [super init];
_cppUnderlying = new Underlying(self);
_dict = [NSMutableDictionary dictionary];
return self;
}
- (void)dealloc
{
delete _cppUnderlying;
}
@end
Underlying.h
@class Wrapper;
class Underlying
{
public:
Underlying(Wrapper* wrapper);
~Underlying();
private:
__weak Wrapper* _wrapper;
};
Underlying.mm
#include "Underlying.h"
#import "Wrapper+Private.h"
Underlying::Underlying(Wrapper* wrapper) :
_wrapper(wrapper)
{
}
Underlying::~Underlying()
{
// ERROR OCCURS HERE.
[_wrapper->_dict setValue:@"value1" forKey:@"key1"];
}
最初,问题是“为什么错误?!”但是,我刚刚发现了这个:Weak property is set to nil in dealloc but property's ivar is not nil其中包含一个详细的解释(基本上,一旦dealloc启动,objc_loadWeak()就会返回nil。)
现在,问题是: 我可以采用什么样的Obj-C设计实践来完全避免这种情况? C ++层在其析构函数中同步处理所有会话清理(如果有的话)。似乎在Objective-C中无法做到同样的事情。在允许用户取消分配实例之前,我是否应该提供“释放”或“关闭”方法来异步执行所有清理工作?
谢谢!
答案 0 :(得分:0)
在-[Wrapper dealloc]
内部,delete _cppUnderlying;
之前,您首先调用类似_cppUnderlying->cleanup(_dict);
的内容,明确地传递字典,甚至_cppUnderlying->cleanup(self);
传递整个内容对象,让Underlying
处理那里的所有清理工作?
答案 1 :(得分:0)
您正在使用nil
运算符取消引用->
:
[_wrapper->_dict setValue:@"value1" forKey:@"key1"];
将_wrapper
测试为nil,或将make dict
更改为可通过点表示法访问的属性:
if (_wrapper) {
[_wrapper->_dict setValue:@"value1" forKey:@"key1"];
}
或
[_wrapper.dict setValue:@"value1" forKey:@"key1"];