0

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

2 回答 2

2

The Apple recommendation is related to modifying the contents of a variable. If you are instead modifying an object referenced by a variable (self.prop in your case) then the question is the same with or without GCD - how do you write a property/method so that it is thread safe?

There are multiple answers to that (@synchronized { }, dispatch_semaphore_X(), NSLock, ...), research ensuring thread safety and find which meets your needs.

于 2013-07-02T22:38:37.480 回答
1

你说:

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

我不确定我会这样说。我认为更合乎逻辑的思考方式是“如果要修改方法的局部变量,则应__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从该块中修改最干净最安全的方法是什么?

从技术上讲,您可以对其进行修改。但是,诀窍是,如果您有多个线程可能同时访问它,那么您将通过其中一种锁定机制同步您与该类属性的交互,或者您可以通过执行与该类属性的所有交互来消除该锁定代码使用串行队列(您创建的串行队列或主队列)。

使用原子设置器?

这只适用于简单的数据类型。但是,在处理对象时,原子二传手不会给你带来太多好处。您需要一些其他机制来同步与变量的交互,例如上面描述的那些。

将块包裹在块中?

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

调度回主线程?

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

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

有很多不同的模式,一个假设的问题很难回答,因为细节完全不同,具体取决于业务需求是什么。对于最佳实践,我建议您观看 Rob Mayoff 引用的 WWDC 视频,Asynchronous Design Patterns with Blocks, GCD, and XPC。您还可以查看 WWDC 2012 Building Concurrent User Interfaces on iOS。这些也建立在早期视频的概念之上,例如 WWDC 2011 视频,例如Blocks 和 Grand Central Dispatch in PracticeMastering Grand Central Dispatch

于 2013-07-03T08:09:27.893 回答