所以我有:
@interface testAppControl : NSObject
{
NSString *s;
}
然后在我的块中我想做
[SendAPI setGroupWithName:groupName completionHandler:^(NSArray *errors) {
s = @"something";
}];
NSLog(@"%@", s); //<--- s is null
所以我想在离开块后保留值"something"
。这可能与ARC有关吗?
答案 0 :(得分:3)
将其声明为__block
变量,然后您可以在块外使用它并在块内更改它。
__block NSString *s = nil;
void(^block)(void) = ^ {
s = @"something";
};
block();
NSLog(@"%@", s);
s = @"blah";
NSLog(@"%@", s);
block();
NSLog(@"%@", s);
答案 1 :(得分:3)
completionHandler
的出现可能导致人们逻辑推断setGroupWithName
是一种异步方法。这是iOS开发中常见的编程模式:不是在前台执行一些可能耗时的过程(在此期间用户界面将被冻结),而是在后台异步执行,但是pass it a block,{{1}在这种情况下,您可以确定异步过程完成时应该发生什么。
在这种情况下,看起来你正在某个后台线程/队列上调用completionHandler
,并且理解当发生这种情况时,你将继续主线程(在你的情况下,在那个{ {1}}语句),确保您的应用程序在缓慢的操作完成时保持响应。但是当setGroupWithName
的异步后台操作完成后,它将执行NSLog
所代表的代码块(在您的情况下,setGroupWithName
到completionHandler
的设置)
如果您在s
区块中放置@"something"
语句,您将NSLog
设置为completionHandler
,您可能会发现它发生得很好在调用s
之后的现有@"something"
语句之后。
为了举例说明,下面是一个标准Cocoa方法的示例,该方法具有NSLog
参数,即setGroupWithName
类方法sendAsynchronousRequest
。
问题是如何执行慢速操作,但仍然具有响应的用户界面,而无需等待慢速的Internet操作。
因此,请考虑以下代码:
completionHandler
这段代码的细节不是很重要,但基本的想法是它做的很慢(在互联网上执行Twitter搜索),但它会立即继续在主线程中运行代码,让后台线程继续按照自己的节奏。
各种NSURLConnection
语句的时间戳说明了所有这些的时间:
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搜索几乎需要一秒钟才能完成。设计原则是,如果我们不是异步执行此操作,在这种情况下使用- (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]);
}
,应用程序的用户界面将被冻结一秒钟。但是通过使用异步编程技术,应用程序仍然很好并且响应迅速,而是在后台执行慢速操作。
我不熟悉你的NSLog
方法,但它可能会执行相同类型的异步操作。因此,您尝试立即查看该值后的值将不会反映该方法完成后将更改的值(类似于我的示例中的“end”NSLog语句未反映将发生的更改的事实第二次)。
答案 2 :(得分:0)
不完全清楚为什么以及你想做什么,所以我给你3个选择:
s
,它将被复制到内部
自动在块内__block
使其仅在块内“可见”答案 3 :(得分:0)
当您执行异步操作时,当调用完成块时,您已经离开了定义s
的函数/范围。
考虑在“全局”范围内声明s
(如类变量或属性),只要您的类实例处于活动状态,您就可以读取该块设置的结果。
我建议使用一个属性,并在块中捕获一个“弱自我”指针,以避免在保存s
的实例被解除分配的情况下访问内存不良。