我想在屏幕上显示我从互联网上拍摄的图像。我用过 NSURLConnection创建一个异步调用来获取数据,并在响应块中调用代码将其分配给UIImage对象。
我的问题是为什么在块执行后我需要调用sleep(1)?如果我没有打电话,那么我的图像不会在屏幕上绘制。这是另一种更优雅的方式吗?
-(void)loadImage:(NSString *)url
{
NSURL *imageURL = [NSURL URLWithString:url];
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageURL cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:5.0f];
[NSURLConnection sendAsynchronousRequest:imageRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if(!connectionError) {
if(data) {
//there goes the main thingy
self.myView.wallpaperImage = [UIImage imageWithData:data];
[self.myView setNeedsDisplay];
} else {
NSLog(@"No data found at url:%@",url);
}
} else {
NSLog(@"Could not connect to %@",url);
}
}];
sleep(1);
}
答案 0 :(得分:2)
此:
self.myView.wallpaperImage = [UIImage imageWithData:data];
[self.myView setNeedsDisplay];
发生在由传递给sendAsynchronousRequest的NSOperationQueue管理的线程上。需要从主线程调用这些方法。 你的睡眠可能导致主线程的runloop迭代,之后这些调用似乎有效。 要解决这个问题,并避免当前的方法会遇到大量其他问题,请执行以下操作:
[NSURLConnection sendAsynchronousRequest:imageRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if([data length] > 0) {
//there goes the main thingy
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.myView.wallpaperImage = [UIImage imageWithData:data];
[self.myView setNeedsDisplay];
}];
} else {
// Perform your error handling here.
}
}];
这将使用[NSOperationQueue mainQueue]
从主队列执行那些UIKit调用 - 而不是libdispatch。 libdispatch是一个低级接口,建议最佳做法是始终使用更高级别的接口 - 在本例中为NSOperationQueue。从主线程(或队列)调用时,UIKit才是安全的。
它还会更改您的错误处理行为,以跟随best的practices platform - 检查您的调用结果(在本例中为数据),然后处理返回的任何错误。
您的代码实际上是块保留捕获对象(在本例中为self)的原因的一个很好的示例。如果此处没有保留周期,ARC可能会在超出范围时立即销毁queue
,并且块将永远不会执行。相反,由于保留周期,队列保持不变,直到块执行完毕。