使用GCD修改对象/外部变量最干净最安全的方法

时间:2013-07-02 22:26:27

标签: objective-c grand-central-dispatch

Apple建议使用静态全局或__block存储类型修改外部变量。

dispatch_async()需要一个没有参数的块。

从该块中修改self.prop最干净最安全的方法是什么?

使用原子设定器?

将块包裹在块中?

发回主线程?

我的情景: 该块正在发出网络请求。 当它完成后,我必须解析一些返回的数据并在几个不同的对象上设置属性,以便我可以跟进网络请求。 正在处理块异步,但根据用户输入,可以使用第一个块所需的数据将第二个块提交给队列。 这就是我想做的事。

@implementation MyNetworkManager {
  dispatch_queue_t op_queue;
  NSURL *_redirectedURL;
}

void (^initPageOperation) (void) = ^(void) {
  NSURL *url;
  NSMutableURLRequest *urlRequest;
  url = [NSURL URLWithString:domain];
  urlRequest =
  [NSMutableURLRequest requestWithURL:url
                          cachePolicy:NSURLRequestUseProtocolCachePolicy
                      timeoutInterval:5];
  [urlRequest setHTTPMethod:@"GET"];

  NSData *data = nil;
  NSURLResponse *urlResponse = nil;
  NSError *err = nil;

  data = [NSURLConnection sendSynchronousRequest:urlRequest
                               returningResponse:&urlResponse
                                           error:&err];

  if (urlResponse) {
     if (![urlResponse.URL isEqual:url]) {
            //Here's where I want to set the redirectedURL.
            _redirectedURL = urlResponse.URL;
     }
   }
};

2 个答案:

答案 0 :(得分:2)

Apple建议与修改变量的内容有关。如果您正在修改引用的对象(在您的情况下为self.prop),那么无论是否使用GCD,问题都是相同的 - 您如何编写属性/方法以便它线程安全吗?

有多个答案(@synchronized { }dispatch_semaphore_X()NSLock,...),确保线程安全并找到符合您需求的研究。

答案 1 :(得分:1)

你说:

  

Apple建议使用静态全局或__block存储类型修改外部变量。

我不确定我会这么说。我认为更合乎逻辑的思考方式是“如果你想修改方法的局部变量,你可以在该变量的声明中使用__block限定符,但不需要该限定符”。简而言之,类实例变量(或属性),__block变量,全局变量等不需要static限定符。

你继续说:

  

dispatch_async()需要一个没有参数的块。

当然,那是真的。但是,再次,如果您正在编写自己的完成块,则可以将它们定义为具有参数。或者您可以使用具有自己的完成块类型的API调用及其自己的参数。例如:

[NSURLConnection sendAsynchronousRequest:request
                                   queue:queue
                       completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
                           // here you can initiate the parse of the data,
                           // capturing the url from the response, or examining
                           // the error
                       }];

completionHandler是一个带参数的块。

所以,是的,一个简单的dispatch_async(或NSOperationQueue等价物,addOperationWithBlock)不带参数,当你开始编写自己的完成块时,你会经常写带参数的那些。

  

从该区块内修改self.prop最干净最安全的方法是什么?

从技术上讲,你可以修改它。但是,诀窍在于,如果您有多个线程同时可以访问它,那么您可以通过locking mechanisms中的一个来同步与该类属性的交互,或者您可以eliminate that locking code by performing all interaction with that class property with a serial queue(串行)您创建的队列或主队列。)

  

使用原子设定器?

仅适用于simple data types。但是,在处理对象时,原子设置器并不会给你带来太大的影响。您需要一些其他机制来同步与变量的交互,例如上面描述的那些。

  

将块包裹在块中?

排序,但技术上并不是将它包装在提供线程安全性的块中,而是将该块分派给一个串行队列(并确保与该属性的所有其他交互都在同一个串行队列上完成)。

  

发回主线程?

在某些简单的情况下,是的,那也可以完成这项工作。但请确保您没有向主线程发送任何非常耗时的内容,否则您的UI可能会受到影响(或更糟)。

  

我有一个假设的情景。一般来说,我试图了解块的最佳实践。

有许多不同的模式,一个假设的问题很难回答,因为细节完全取决于业务需求的确切含义。为了获得最佳实践,我建议您观看引用的WWDC视频Rob Mayoff Asynchronous Design Patterns with Blocks, GCD, and XPC。您还可以看到WWDC 2012 Building Concurrent User Interfaces on iOS。这些也基于早期视频的概念,例如WWDC 2011视频,例如Blocks and Grand Central Dispatch in PracticeMastering Grand Central Dispatch