2013-04-30 64 views
0

坏访问看到这个代码示例:GCD - 在主队列

dispatch_queue_t downloadQueue=dispatch_queue_create("test", NULL); 

     dispatch_async(downloadQueue, ^{ 

      //do some core data fetching stuff 
      //create UIImage    

      //Need to go back to the main thread since this is UI related 
      dispatch_async(dispatch_get_main_queue(), ^{ 

        if(someView) 
        { 
         [someView addSubview:self]; 
        } 
       } 

      }); 
     }); 
     dispatch_release(downloadQueue); 

如果“someView”不这段代码的主线程部分运行的时间有哪些?显然这会导致EXC_BAD_ACCESS崩溃,但我想知道处理这种情况的最佳方法是什么。当用户导航到需要几秒钟加载的页面时,通常会发生这种情况,但在当前页面仍在加载时决定返回到上一页。

我可以想象在尝试添加子视图之前需要检查某种全局标志,但这似乎很难。现在

+2

如果你使用ARC并且'someView'被声明为'weak'引用,那么如果对象被释放,它将是'nil'。这将避免保持对不再存在的视图的引用的问题。 – rmaddy 2013-04-30 16:19:38

+0

这是正确的。我将该属性定义为“分配”而不是弱。改变为弱解决了这个问题。 – soleil 2013-04-30 16:33:58

+0

在ARC中使用“assign”有效地消除了ARC的所有优势! :) – matt 2013-04-30 17:08:11

回答

0
dispatch_async(downloadQueue, ^{ 
    UIView* v = someView; 

,如果在这一刻一直办下去,如果你正在使用ARC,v是零,您可以测试这一点。另一方面,如果存在,并且您正在使用ARC,那么v就是一个强烈的参考,并且对于块嵌套的其余部分它不会失去存在。然后,您可以(在此时或之后在块的主线程部分中)询问v.window以发现视图是否仍在界面中;如果没有,这是不值得的。

+0

如果使用ARC,那么执行:'__weak UIView * v = someView'解决了这个问题。只要'v'的对象引用被解除分配,'v'将被自动设置为'nil'。 – rmaddy 2013-04-30 17:05:53

+0

@rmaddy不是线程安全的。在块运行时,'someView'的状态可能会改变*。因此,没有测试是有效的:你可以说'if(v)'并且得到一个非零的'v',但是通过从另一个线程中取消分配''v''从你之下抽出'v'。这就是为什么你应该总是通过块内的强引用重新捕获:如果它是非零*然后*,它将在块的其余部分保持非零。 – matt 2013-04-30 17:10:58

0
// Capture a strong reference to someView, to make sure it's still around later on. 
__block UIView *v = someView; 

//Need to go back to the main thread since this is UI related 
dispatch_async(dispatch_get_main_queue(), ^{ 
    [v addSubview:self] 
    // Release v (assuming ARC). If nothing else has retained someView, this means 
    // that someView will be deallocated - but we're on the main thread, 
    // so that's fine. What we don't want is a background dealloc. 
    v = nil; 
}); 

OR

// Capture a strong reference to someView, to make sure it's still around later on. 
__weak UIView *weakRef = someView; 


//Need to go back to the main thread since this is UI related 
dispatch_async(dispatch_get_main_queue(), ^{ 
    // This is thread-safe because someView should only be de-alloced on the main thread. 
    // consequently our access to weakRef is safe. 
    UIView *strongRef = weakRef; 
    [strongRef addSubview:self]; 
}); 

什么不可以做的就是这个。

UIView *strongRef = whatever; 
    dispatch_async(downloadQueue, ^{ 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      [someView addSubview:self] 
     }); 
     // If, by the time we get here, the dispatch to the main queue has already run, 
     // then we will send a release to someView on a background thread. If it's the last 
     // remaining reference - and it might be, unlikely as it is, then we just dealloced 
     // a UIView in the background. This is bad. 
    });