gpt4 book ai didi

ios - 与 iOS 中的 setter/getter 相关的奇怪的 EXC_BAD_ACCESS 崩溃

转载 作者:行者123 更新时间:2023-11-28 18:34:37 24 4
gpt4 key购买 nike

有人可以解释为什么我的代码会崩溃吗?崩溃发生在 foo 方法的 block 内。我有 EXC_BAD_ACCESS 或“对象错误:双重释放”。当我将“启用僵尸对象”设置为 ON 时,我还收到了“-[NSObject 描述]:发送到已释放实例的消息”。

@interface ViewController ()
@property (nonatomic, strong) NSObject *obj;
@end

@implementation ViewController

// just adding button
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
[btn setTitle:@"test" forState:UIControlStateNormal];
btn.frame = CGRectMake(100, 100, 100, 100);
[btn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
}

// fired by button
- (void)btnAction:(id)sender {
for (int i = 0; i < 100; i++) {
[self foo];
}
}

// I want to understand this method
- (void)foo {
NSLog(@"foo");

self.obj = NSObject.new;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"%@", [[self obj] description]); // sometimes crash happenes here with a message "-[NSObject description]: message sent to deallocated instance"
});
}

@end

看起来 self.obj 在 [self obj] 和 [obj description] 之间被释放了。但我不确定为什么。

我认为来自 [self obj] 的对象应该由它的范围拥有并且不应该被释放,即使 self.obj = NSObject.new 在其他线程上同时执行也是如此。我的理解有误吗?

我正在使用 ARC 在 iOS 7.0.4 上进行测试。谢谢!

最佳答案

您有一个调用 -foo 方法的 for 循环,因此 self.obj 会迅速设置为新值。每次发生这种情况时,您都在异步执行访问您的 (nonatomic) 属性的代码。但是,即使在从多个线程访问时始终为该属性获取正确的值,主线程也很可能在后台线程使用完该属性的先前值之前将该属性设置为新值。一旦该属性更改为新值,它就会释放之前分配给它的对象。

由于您从多个线程访问您的属性,您希望它是原子的,而不是非原子的,因此将您的属性更改为:

@property (strong) NSObject *obj;

atomic 是默认值。使用异步 block 执行以下操作可能也更安全:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSObject *obj = self.obj;
if (self.obj) {
NSLog(@"%@", [obj description]);
}
});

如果您这样做,您应该不会再看到崩溃,因为 obj 将始终是 nil 或在 block 内对其具有强引用的有效对象。

但是,您可能无法从中获得预期的结果。对于异步 block 的每次执行,不能保证您将获得正在创建的 NSObject 的后续实例。有时它会执行您的 block ,其中 obj 两次都是同一个对象,并且您永远看不到创建的某些对象。这是因为您的异步 block 没有在您调用调用 block 之前立即设置实例,而是从属性中获取实例。如果您希望它立即使用之前设置的实例,则必须执行以下操作:

__block NSObject *obj = NSObject.new;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"%@", [obj description]);
});

这应该始终使用您专门为异步 block 调用创建的实例。

关于ios - 与 iOS 中的 setter/getter 相关的奇怪的 EXC_BAD_ACCESS 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21532168/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com