从dealloc内部间接访问弱ivar时如何避免EXC_BAD_ACCESS错误

时间:2015-04-13 18:32:43

标签: ios objective-c xcode objective-c++

我有一个包装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中无法做到同样的事情。在允许用户取消分配实例之前,我是否应该提供“释放”或“关闭”方法来异步执行所有清理工作?

谢谢!

2 个答案:

答案 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"];