繁体   English   中英

使用dispatch_async奇怪的bad_access

[英]Weird bad_access with dispatch_async

使用调度异步时,我收到了一个非常奇怪的错误访问错误。 我设法将其缩减为程序中的这段代码。

-(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;
}

该代码最初看起来不是这样,但是现在是这样。 包括分配虚拟NSObject。

foo如何在调度异步内部的调用之间释放? 我不明白这怎么可能。 我知道很难建议仅此而已,但是任何调试建议都将有所帮助。 我尝试打开NSZombies,但没有任何僵尸。

你问:

foo如何在dispatch_async内部的dispatch_async调用之间被释放?

除非someMethodsecondMethod自己进行,否则不应该异步执行某些操作,这可能会使自动释放池在此期间耗尽。

我尝试打开NSZombies但没有任何僵尸。

如果您打开了僵尸,但又没有遇到僵尸,那么我怀疑问题出在其他地方。 坦率地说,我怀疑问题的根源在简化示例代码以解决问题的过程中被消除了:

其他一些观察/说明:

  1. 您声明fooNSArray ,但随后返回NSObject 我假设您的意思是整个都是NSObject

  2. 您有一行代码说:

     dispatch_async(dispatch_get_main_queue(),0) { 

    我只是假设这是一个错字,并且您打算这样做:

     dispatch_async(dispatch_get_main_queue(), ^{ 
  3. foo变量一定应该在dispatch_async块内。 __block变量用于某个东西(a),您没有在该块之外为某个块引用,这实际上没有任何意义。 (b)对于您异步分发的代码块。

  4. secondMethod应该返回一个autorelease对象,就像您最初拥有的那样。 (或者你可能想改变secondMethodsomeMethod开始与new的自己的名字,以避免混淆,使生活为自己容易当你最终会转移到ARC)。

  5. 如果retain foo对象,则还需要添加相应的release 实际上,您的原始代码示例返回一个+1对象,然后再次将其保留,将其增大到+2,因此您需要两次release调用。

无论如何,要纠正这些各种问题,我得到以下结果,它不会产生异常:

- (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];
}

此外,我建议特别是在使用手动保留和释放(MRR)时,通过静态分析器(在Xcode“产品”菜单上的“分析”)运行它,并确保您的健康状况良好。 (它会指出我提到的一些问题。)它不是完美的,但在识别问题方面非常出色。

但是,简而言之,上面的代码很好,并且如果您仍然遇到异常,请使用可重现异常的工作代码来更新您的问题。

暂无
暂无

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

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