如何保留在块中设置的局部变量? [英] How can I retain a local variable that is set in a block?

查看:103
本文介绍了如何保留在块中设置的局部变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我有

@interface testAppControl : NSObject
{
    NSString *s;
}

然后在我要阻止的地方

[SendAPI setGroupWithName:groupName completionHandler:^(NSArray *errors) {
    s = @"something";
}];

NSLog(@"%@", s); //<--- s is null

所以我想在离开块后保留值"something". ARC是否可能?

So I want to keep the value "something" after I leave my block. Is this possible with ARC?

推荐答案

completionHandler的存在可能会导致人们从逻辑上推断setGroupWithName是一种异步方法.这是iOS开发中的一种常见编程模式:与其在前台执行一些潜在的耗时过程(在此过程中将冻结用户界面),不如在后台异步执行它,而是

The very presence of completionHandler might lead one to logically infer that setGroupWithName is an asynchronous method. This a common programming pattern in iOS development: Rather than perform some potentially time consuming process in the foreground (during which the user interface would be frozen), perform it asynchronously in the background, but pass it a block, the completionHandler in this case, so you can identify what should take place when the asynchronous process is complete.

在这种情况下,您似乎在某些后台线程/队列上调用setGroupWithName,但要了解,在这种情况下,您将继续在主线程上(在这种情况下,在该NSLog语句),以确保在完成慢速操作后您的应用程序保持响应状态.但是setGroupWithName的异步后台操作完成后,它将执行completionHandler表示的代码块(在您的情况下,将s设置为@"something").

In this case, it looks like you're invoking setGroupWithName, on some background thread/queue with the understanding that while that's happening, you'll continue on the main thread (in your case, at that NSLog statement), ensuring that your app stays responsive while that slow operation is being completed. But when that asynchronous background operation of setGroupWithName is done, it will perform the block of code represented by the completionHandler (in your case, the setting of s to @"something").

如果将NSLog语句放在completionHandler块内,则将s设置为@"something",您可能会发现在现有的NSLog语句之后,它发生得很好调用setGroupWithName之后具有.

If you put a NSLog statement inside the completionHandler block, where you're setting s to @"something", and you'll probably see that it is happening well after the existing NSLog statement you have after the invocation of setGroupWithName.

为了说明该示例,这是一个具有completionHandler参数的标准可可方法的示例,即NSURLConnection类方法

To illustrate the example, here is an example of a standard Cocoa method that has a completionHandler parameter, namely the NSURLConnection class method, sendAsynchronousRequest.

问题是如何执行缓慢的操作,但仍然具有可响应的用户界面,而无需等待缓慢的Internet操作.

The question is how to perform a slow operation, but still have a user interface that is responsive without waiting for the slow Internet operation.

因此,请考虑以下代码:

So, consider the following code:

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

这段代码的细节不是很重要,但是基本思想是它的运行速度很慢(在Internet上执行Twitter搜索),但是它将立即继续在主线程中运行代码,让后台线程保持自己的步调.

The details of this code aren't very important, but the basic idea is that it's doing something slow (performing a Twitter search on the Internet), but it will immediately continue running code in the main thread, letting the background thread carry on at its own pace.

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

The timestamps of the various NSLog statements is illustrate the timing of all of this:


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: array still has 0 items
2013-05-02 20:42:59.798 myapp[81642:1303] __32-[ViewController performSearch:]_block_invoke: after background query, array now has 11 items

请注意,从开始"到结束"之间的时间大约为1毫秒,但是在后台完成Twitter搜索大约需要整整一秒钟.设计原则是,如果不使用completionHandler异步执行此操作,则该应用程序的用户界面将被冻结一秒钟.但是,通过使用异步编程技术,该应用程序仍然保持了良好的响应速度,但是却在后台执行了缓慢的操作.

Note that the time elapsed between the "start" and the "end" is roughly 1 millisecond, but the completion of the Twitter search in the background took almost a full second to complete. The design principle is that if we didn't do this asynchronously, using the completionHandler in this case, the app's user interface would have been frozen for that one second. But by using asynchronous programming techniques, the app remained nice and responsive, but rather performed the slow operation in the background.

我不熟悉您的setGroupWithName方法,但是它大概在执行相同类型的异步操作.因此,您尝试立即查看后置值的尝试将不会反映该方法完成后将更改的值(有点像这样的事实,在我的示例中,"end" NSLog语句未反映将要发生的更改.第二秒).

I'm not familiar with your setGroupWithName method, but it is presumably performing the same sort of asynchronous operation. Thus your attempt to look at the value immediately afterword will not reflect the value that will change once that method is done (kind of like the fact that the "end" NSLog statement in my example doesn't reflect the change that will take place one second later).

这篇关于如何保留在块中设置的局部变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆