简体   繁体   English

使用dispatch_async奇怪的bad_access

[英]Weird bad_access with dispatch_async

I'm getting a really weird bad access error while using dispatch async. 使用调度异步时,我收到了一个非常奇怪的错误访问错误。 I managed to reduce it down to this segment of code in my program. 我设法将其缩减为程序中的这段代码。

-(void)buttonTapped:(id)sender {

    __block NSArray*foo = nil;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        //Foo was initially declared here but then moved it outside.
        foo = [self someMethod];
        [foo retain]; // bad access here. Why ?
        dispatch_async(dispatch_get_main_queue(),0) {
            // doesnt matter what happens here
    }); });
}

-(id)someMethod 
{
    return [self secondMethod];
}

-(id)secondMethod
{
    // was initially returning an autoreleased object from here. Changed it
    // to eliminate that as source of the error.
    id newThing = [[NSObject alloc] init];
    return newThing;
}

The code didnt initially look like this but this is how it is right now . 该代码最初看起来不是这样,但是现在是这样。 Including allocating a dummy NSObject . 包括分配虚拟NSObject。

How is it possible for foo to get released in between calls inside a dispatch async ? foo如何在调度异步内部的调用之间释放? I dont understand how this is possible. 我不明白这怎么可能。 I know its difficult to suggest whats going from just this but any debugging suggestions would be helpful. 我知道很难建议仅此而已,但是任何调试建议都将有所帮助。 I tried turning on NSZombies but I dont get any Zombies. 我尝试打开NSZombies,但没有任何僵尸。

You ask: 你问:

How is it possible for foo to get released in between calls inside a dispatch_async ? foo如何在dispatch_async内部的dispatch_async调用之间被释放?

It shouldn't, unless someMethod or secondMethod are, themselves, doing something asynchronously which might allow the autorelease pool to be drained in the interim. 除非someMethodsecondMethod自己进行,否则不应该异步执行某些操作,这可能会使自动释放池在此期间耗尽。

I tried turning on NSZombies but I dont get any Zombies. 我尝试打开NSZombies但没有任何僵尸。

If you've got zombies turned on and you're not getting a zombie, then I suspect the problem rests elsewhere. 如果您打开了僵尸,但又没有遇到僵尸,那么我怀疑问题出在其他地方。 Frankly, I suspect that the root of the problem was eliminated in your process of simplifying the sample code for the purposes of the question: 坦率地说,我怀疑问题的根源在简化示例代码以解决问题的过程中被消除了:

A few other observations/clarifications: 其他一些观察/说明:

  1. You declared foo to be a NSArray , but then you're returning NSObject . 您声明fooNSArray ,但随后返回NSObject I'll assume you meant it to be NSObject throughout. 我假设您的意思是整个都是NSObject

  2. You have a line of code that says: 您有一行代码说:

     dispatch_async(dispatch_get_main_queue(),0) { 

    I'll just assume that was a typo and that you intended: 我只是假设这是一个错字,并且您打算这样做:

     dispatch_async(dispatch_get_main_queue(), ^{ 
  3. The foo variable should definitely be inside the dispatch_async block. foo变量一定应该在dispatch_async块内。 It doesn't really make sense to have a __block variable for something (a) you don't reference outside of that block for a block; __block变量用于某个东西(a),您没有在该块之外为某个块引用,这实际上没有任何意义。 and (b) for a block you're dispatching asynchronously. (b)对于您异步分发的代码块。

  4. The secondMethod should return an autorelease object, as you apparently originally had it. secondMethod应该返回一个autorelease对象,就像您最初拥有的那样。 (Or you'd probably want to change secondMethod and someMethod to start with new in their names to avoid confusion and make life easier for yourself when you eventually move to ARC.) (或者你可能想改变secondMethodsomeMethod开始与new的自己的名字,以避免混淆,使生活为自己容易当你最终会转移到ARC)。

  5. If you retain the foo object, you'll want to also add the appropriate release . 如果retain foo对象,则还需要添加相应的release In fact, your original code sample returns a +1 object, and then retain it again, bumping it to +2, so you'd need two release calls. 实际上,您的原始代码示例返回一个+1对象,然后再次将其保留,将其增大到+2,因此您需要两次release调用。

Anyway, correcting for these various issues, I end up with the following, which does not generate an exception: 无论如何,要纠正这些各种问题,我得到以下结果,它不会产生异常:

- (IBAction)buttonTapped:(id)sender
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{

        NSObject *foo = [self someMethod];
        [foo retain]; // no bad access here

        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"foo = %@", foo);

            [foo release];
        });
    });
}

- (NSObject *)someMethod
{
    return [self secondMethod];
}

- (NSObject *)secondMethod
{
    return [[[NSObject alloc] init] autorelease];
}

Furthermore, I would suggest, especially when using manual retain and release (MRR), that you run it through the static analyzer ("Analyze" on the Xcode "Product" menu) and make sure you have a clean bill of health. 此外,我建议特别是在使用手动保留和释放(MRR)时,通过静态分析器(在Xcode“产品”菜单上的“分析”)运行它,并确保您的健康状况良好。 (It would have pointed out some of the issues I mentioned.) It's not perfect, but it's remarkably good at identifying issues. (它会指出我提到的一些问题。)它不是完美的,但在识别问题方面非常出色。

But, in short, the above code is fine, and if you're still getting an exception, update your question with working code that reproduces the exception. 但是,简而言之,上面的代码很好,并且如果您仍然遇到异常,请使用可重现异常的工作代码来更新您的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM