我有一个带有UIImageView子视图的UIView.我需要在UIImageView中加载图像而不阻止UI.阻塞呼叫似乎是:UIImage imageNamed:.以下是我认为解决这个问题的方法:
-(void)updateImageViewContent {
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
UIImage * img = [UIImage imageNamed:@"background.jpg"];
dispatch_sync(dispatch_get_main_queue(), ^{
[[self imageView] setImage:img];
});
});
}
Run Code Online (Sandbox Code Playgroud)
图像很小(150x100).
但是,加载图像时仍然会阻止UI.我错过了什么?
这是一个展示此行为的小代码示例:
基于UIImageView创建一个新类,将其用户交互设置为YES,在UIView中添加两个实例,并实现其touchesBegan方法,如下所示:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (self.tag == 1) {
self.backgroundColor= [UIColor redColor];
}
else {
dispatch_async(dispatch_get_main_queue(), ^{
[self setImage:[UIImage imageNamed:@"woodenTile.jpg"]];
});
[UIView animateWithDuration:0.25 animations:
^(){[self setFrame:CGRectInset(self.frame, 50, 50)];}];
}
}
Run Code Online (Sandbox Code Playgroud)
将标记1分配给其中一个imageView.
从加载图像的视图开始几乎同时点击两个视图时会发生什么?UI是否因为等待[self setImage:[UIImage imageNamed:@"woodenTile.jpg"]];返回而被阻止?如果是这样,我该如何异步执行此操作?
这是一个 带有ipmcc代码的github项目
使用长按然后拖动在黑色方块周围绘制一个矩形.据我理解他的答案,理论上白色选择矩形不应该在第一次加载图像时被阻挡,但实际上是.
项目中包含两个图像(一个小图片:woodenTile.jpg和一个较大图片:bois.jpg).结果与两者相同.
我真的不明白这与第一次加载图像时UI被阻止的问题有什么关系,但是PNG图像在不阻挡UI的情况下进行解码,而JPG图像会阻止UI.

UI的阻止从这里开始..

..并在此结束.

NSURL * url = …Run Code Online (Sandbox Code Playgroud) 我的程序显示一个水平滚动表面,从左到右平铺UIImageViews.代码在UI线程上运行,以确保新显示的UIImageViews分配了一个新加载的UIImage.加载发生在后台线程上.
一切都很好,除了每个图像变得可见时都有口吃.起初我以为我的后台工作者在UI线程中锁定了一些内容.我花了很多时间查看它,并最终意识到UIImage在UI线程第一次变得可见时正在做一些额外的延迟处理.这让我很困惑,因为我的工作线程有明确的解压缩JPEG数据的代码.
无论如何,在预感上,我写了一些代码,以渲染到后台线程上的临时图形上下文中 - 当然,口吃也消失了.UIImage现在正在我的工作线程上预先加载.到现在为止还挺好.
问题是我的新"强力懒惰的图像"方法是不可靠的.它会导致间歇性的EXC_BAD_ACCESS.我不知道UIImage在幕后实际上在做什么.也许它正在解压缩JPEG数据.无论如何,方法是:
+ (void)forceLazyLoadOfImage: (UIImage*)image
{
CGImageRef imgRef = image.CGImage;
CGFloat currentWidth = CGImageGetWidth(imgRef);
CGFloat currentHeight = CGImageGetHeight(imgRef);
CGRect bounds = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
CGAffineTransform transform = CGAffineTransformIdentity;
CGFloat scaleRatioX = bounds.size.width / currentWidth;
CGFloat scaleRatioY = bounds.size.height / currentHeight;
UIGraphicsBeginImageContext(bounds.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextScaleCTM(context, scaleRatioX, -scaleRatioY);
CGContextTranslateCTM(context, 0, -currentHeight);
CGContextConcatCTM(context, transform);
CGContextDrawImage(context, CGRectMake(0, 0, currentWidth, currentHeight), imgRef);
UIGraphicsEndImageContext();
}
Run Code Online (Sandbox Code Playgroud)
并且EXC_BAD_ACCESS发生在CGContextDrawImage行上.问题1:我是否允许在UI线程以外的线程上执行此操作?问题2:什么是UIImage实际上"预加载"?问题3:解决这个问题的官方方法是什么?
感谢阅读所有这些,任何建议将不胜感激!
我在每个单元格中都有UITableView图像,我希望滚动顺畅.所以我在stackerflow上阅读了一些帖子,现在我在后台线程中加载我的图片:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: BuildingStatusCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! BuildingStatusCell
cell.selectionStyle = UITableViewCellSelectionStyle.None
var node = nodesArray[indexPath.row] as! NSMutableDictionary
if !checkIfImagesLoaded(node[Api.pictures] as! NSMutableArray) {
cell.id = node[Api.buildingStatusId] as! Int
cell.date.text = node[Api.date] as? String
cell.count.text = String((node[Api.pictures] as! NSMutableArray).count)
cell.indicator.hidesWhenStopped = true
cell.indicator.startAnimating()
dbHelper.getBuildingStatusNode(node, callback: self)
} else {
cell.id = node[Api.buildingStatusId] as! Int
cell.date.text = node[Api.date] as? String
cell.count.text = String((node[Api.pictures] as! NSMutableArray).count)
dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_USER_INITIATED.value), 0)) {
var image = …Run Code Online (Sandbox Code Playgroud) ios ×2
cgimage ×1
iphone ×1
lazy-loading ×1
objective-c ×1
swift ×1
uiimage ×1
uiimageview ×1
uitableview ×1