我怎样才能保留一个块中设置的局部variables?

所以我有:

@interface testAppControl : NSObject { NSString *s; } 

然后在我的方块我想要做的

 [SendAPI setGroupWithName:groupName completionHandler:^(NSArray *errors) { s = @"something"; }]; NSLog(@"%@", s); //<--- s is null 

所以我想在离开我的街区之后保留价值"something" 。 这可能与ARC?

将其声明为__blockvariables,然后可以在块外部使用它,并在块内部对其进行更改。

 __block NSString *s = nil; void(^block)(void) = ^ { s = @"something"; }; block(); NSLog(@"%@", s); s = @"blah"; NSLog(@"%@", s); block(); NSLog(@"%@", s); 

completionHandler存在可能导致逻辑上推断出setGroupWithName是一个asynchronous方法。 这是iOS开发中的一种常见的编程模式:在前台执行一些耗时的过程(在此期间用户界面将被冻结),而不是在后台asynchronous执行它,而是传递一个块 ,在这种情况下为completionHandler ,所以您可以确定asynchronous过程完成后应该发生什么。

在这种情况下,它看起来像你调用setGroupWithName ,在一些后台线程/队列,理解,发生这种情况,你会继续在主线程(在你的情况下,在NSLog语句),确保你的应用程序保持响应,而缓慢的操作正在完成。 但是,当setGroupWithNameasynchronous后台操作完成时,它将执行由completionHandler表示的代码块(在你的情况下,将s设置为@"something" )。

如果你在completionHandler块中放置了一个NSLog语句,那么你可能会发现它在调用setGroupWithName之后的现有NSLog语句之后发生了setGroupWithName


为了说明这个例子,下面是一个带有completionHandler参数的标准Cocoa方法的例子,也就是NSURLConnection类的方法sendAsynchronousRequest

问题是如何执行一个缓慢的操作,但仍然有一个响应的用户界面,而不必等待互联网的慢操作。

所以,请考虑以下代码:

 - (void)performSearch:(NSString *)term { NSLog(@"%s start: array has %d items", __FUNCTION__, [self.array count]); // prepare to do search (the details here are not relevant) NSOperationQueue *queue = [[NSOperationQueue alloc] init]; NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://search.twitter.com/search.json?q=%@", term]]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; // submit an Internet search that will be performed in the background [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { // in the background, when the Twitter search is done, // and when it's done, we'll make an array of the results self.array = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; NSLog(@"%s: after background query, array now has %d items", __FUNCTION__, [self.array count]); }]; // in the meantime, let's immediately carry on while that search is taking place NSLog(@"%s end: array still has %d items", __FUNCTION__, [self.array count]); } 

这段代码的细节不是很重要,但基本思想是它做的很慢(在因特网上执行Twittersearch),但是它会立即继续在主线程中运行代码,让后台线程继续自己的步伐。

各种NSLog语句的时间戳说明了所有这些的时间:

 2013-05-02 20:42:58.922 myapp [81642:c07]  -  [ViewController performSearch:] start:array has 0 items
 2013-05-02 20:42:58.923 myapp [81642:c07]  -  [ViewController performSearch:] end:数组仍然有0个项目
 2013-05-02 20:42:59.798 myapp [81642:1303] __32- [ViewController performSearch:] _ block_invoke:后台查询后,数组现在有11个项目

请注意,“开始”和“结束”之间的时间大约为1毫秒,但是在后台完成Twittersearch需要几乎整整一秒的时间。 devise原则是,如果我们不这样做,在这种情况下使用completionHandler ,应用程序的用户界面将被冻结一秒钟。 但通过使用asynchronous编程技术,该应用程序保持良好和响应,而是在后台执行缓慢的操作。

我不熟悉你的setGroupWithName方法,但它大概是执行相同types的asynchronous操作。 因此,你试图看后面的值不会反映一旦完成该方法将会改变的值(有点像我的例子中的“结束”NSLog语句不反映将发生的变化秒以后)。

不完全清楚你为什么想要做什么,所以我给你3个select:

  • 在块外部声明variabless ,它将自动在块内复制
  • 如果你需要改变它的值并读取它在__block说明符的块之外声明它,请注意,如果你在asynchronous过程中改变这个var,块后面的值很可能是无用的
  • 如果要在每次调用块时将其值保持并更改,请将其作为static块放入块中,仅在块内“可见”

当你正在执行一个asynchronous操作,并且在完成块被调用的时候,你已经离开了定义s的函数/范围。

考虑在一个“全局”范围内(如类variables或属性)声明s ,那么只要你的类实例处于活动状态,你将能够读取块设置的结果。

我build议使用一个属性,并在块中捕获一个“弱自我”指针,以避免在持有s的实例被重新分配的情况下访问错误的内存。